feat: CI/CD pipeline + Learning/Medicine/Travel services
- Add Gitea Actions workflow for automated build & deploy - Add K8s manifests: webui, travel-svc, medicine-svc, sandbox-svc - Update kustomization for localhost:5000 registry - Add ingress for gooseek.ru and api.gooseek.ru - Learning cabinet with onboarding, courses, sandbox integration - Medicine service with symptom analysis and doctor matching - Travel service with itinerary planning - Server setup scripts (NVIDIA/CUDA, K3s, Gitea runner) Made-with: Cursor
This commit is contained in:
@@ -39,12 +39,16 @@ func CollectEventsEnriched(ctx context.Context, cfg TravelOrchestratorConfig, br
|
||||
|
||||
events := extractEventsWithLLM(ctx, cfg.LLM, brief, rawResults, crawledContent)
|
||||
|
||||
events = geocodeEvents(ctx, cfg, events)
|
||||
events = geocodeEvents(ctx, cfg, brief, events)
|
||||
|
||||
events = deduplicateEvents(events)
|
||||
|
||||
events = filterFreshEvents(events, brief.StartDate)
|
||||
|
||||
// Hard filter: drop events that ended up in another city/country due to ambiguous geocoding.
|
||||
destGeo := geocodeDestinations(ctx, cfg, brief)
|
||||
events = filterEventsNearDestinations(events, destGeo, 250)
|
||||
|
||||
if len(events) > 15 {
|
||||
events = events[:15]
|
||||
}
|
||||
@@ -425,28 +429,74 @@ func tryPartialEventParse(jsonStr string) []EventCard {
|
||||
return events
|
||||
}
|
||||
|
||||
func geocodeEvents(ctx context.Context, cfg TravelOrchestratorConfig, events []EventCard) []EventCard {
|
||||
func geocodeEvents(ctx context.Context, cfg TravelOrchestratorConfig, brief *TripBrief, events []EventCard) []EventCard {
|
||||
destSuffix := strings.Join(brief.Destinations, ", ")
|
||||
for i := range events {
|
||||
if events[i].Address == "" || (events[i].Lat != 0 && events[i].Lng != 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
geoCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
geo, err := cfg.TravelData.Geocode(geoCtx, events[i].Address)
|
||||
cancel()
|
||||
queries := []string{events[i].Address}
|
||||
if destSuffix != "" && !strings.Contains(strings.ToLower(events[i].Address), strings.ToLower(destSuffix)) {
|
||||
queries = append(queries, fmt.Sprintf("%s, %s", events[i].Address, destSuffix))
|
||||
}
|
||||
queries = append(queries, fmt.Sprintf("%s, %s", events[i].Title, destSuffix))
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[travel-events] geocode failed for '%s': %v", events[i].Address, err)
|
||||
continue
|
||||
var lastErr error
|
||||
for _, q := range queries {
|
||||
geoCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
geo, err := cfg.TravelData.Geocode(geoCtx, q)
|
||||
cancel()
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
events[i].Lat = geo.Lat
|
||||
events[i].Lng = geo.Lng
|
||||
break
|
||||
}
|
||||
|
||||
events[i].Lat = geo.Lat
|
||||
events[i].Lng = geo.Lng
|
||||
if events[i].Lat == 0 && events[i].Lng == 0 {
|
||||
if lastErr != nil {
|
||||
log.Printf("[travel-events] geocode failed for '%s': %v", events[i].Address, lastErr)
|
||||
} else {
|
||||
log.Printf("[travel-events] geocode failed for '%s'", events[i].Address)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
func filterEventsNearDestinations(events []EventCard, destinations []destGeoEntry, maxKm float64) []EventCard {
|
||||
if len(destinations) == 0 {
|
||||
return events
|
||||
}
|
||||
filtered := make([]EventCard, 0, len(events))
|
||||
for _, e := range events {
|
||||
if e.Lat == 0 && e.Lng == 0 {
|
||||
continue
|
||||
}
|
||||
minD := 1e18
|
||||
for _, d := range destinations {
|
||||
if d.Lat == 0 && d.Lng == 0 {
|
||||
continue
|
||||
}
|
||||
dd := distanceKm(e.Lat, e.Lng, d.Lat, d.Lng)
|
||||
if dd < minD {
|
||||
minD = dd
|
||||
}
|
||||
}
|
||||
if minD <= maxKm {
|
||||
filtered = append(filtered, e)
|
||||
} else {
|
||||
log.Printf("[travel-events] dropped far event '%s' (%.0fkm from destinations)", e.Title, minD)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func deduplicateEvents(events []EventCard) []EventCard {
|
||||
seen := make(map[string]bool)
|
||||
var unique []EventCard
|
||||
|
||||
Reference in New Issue
Block a user