Apollo Places: enrich insights with personal place name + notes
Optional integration with the sibling Apollo project's user-defined Places (name + lat/lon + radius_m + description + category). When APOLLO_API_BASE_URL is set, the per-photo location resolver folds the most-specific containing Place into the LLM prompt's location string — "Home (My house in Cambridge) — near Cambridge, MA" rather than the city name alone. Smallest-radius wins; Apollo sorts server-side via /api/places/contains, so the carousel badge in Apollo and the prompt string here always agree. Adds an agentic tool `get_personal_place_at(latitude, longitude)` that the LLM can call during chat continuation. Tool description tells the model the call returns the user's free-text notes, not just a name. Deliberately narrow — no enumerate-all variant, lat/lon required. Unset APOLLO_API_BASE_URL = legacy Nominatim-only path, tool is not registered. 5 s timeout; all errors degrade silently. Tests: 5 unit tests for compose_location_string (Apollo only, Nominatim only, both, both-with-description, neither). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use crate::ai::insight_chat::{ChatLockMap, InsightChatService};
|
||||
use crate::ai::openrouter::OpenRouterClient;
|
||||
use crate::ai::apollo_client::ApolloClient;
|
||||
use crate::ai::{InsightGenerator, OllamaClient, SmsApiClient};
|
||||
use crate::database::{
|
||||
CalendarEventDao, DailySummaryDao, ExifDao, InsightDao, KnowledgeDao, LocationHistoryDao,
|
||||
@@ -155,6 +156,11 @@ impl Default for AppState {
|
||||
let sms_api_token = env::var("SMS_API_TOKEN").ok();
|
||||
let sms_client = SmsApiClient::new(sms_api_url, sms_api_token);
|
||||
|
||||
// Apollo Places integration. Optional — when APOLLO_API_BASE_URL is
|
||||
// unset, ApolloClient is constructed disabled and the insight
|
||||
// generator silently falls through to the legacy Nominatim path.
|
||||
let apollo_client = ApolloClient::new(env::var("APOLLO_API_BASE_URL").ok());
|
||||
|
||||
// Initialize DAOs
|
||||
let insight_dao: Arc<Mutex<Box<dyn InsightDao>>> =
|
||||
Arc::new(Mutex::new(Box::new(SqliteInsightDao::new())));
|
||||
@@ -193,6 +199,7 @@ impl Default for AppState {
|
||||
ollama.clone(),
|
||||
openrouter.clone(),
|
||||
sms_client.clone(),
|
||||
apollo_client.clone(),
|
||||
insight_dao.clone(),
|
||||
exif_dao.clone(),
|
||||
daily_summary_dao.clone(),
|
||||
@@ -295,6 +302,7 @@ impl AppState {
|
||||
None,
|
||||
);
|
||||
let sms_client = SmsApiClient::new("http://localhost:8000".to_string(), None);
|
||||
let apollo_client = ApolloClient::new(None);
|
||||
|
||||
// Initialize test DAOs
|
||||
let insight_dao: Arc<Mutex<Box<dyn InsightDao>>> =
|
||||
@@ -327,6 +335,7 @@ impl AppState {
|
||||
ollama.clone(),
|
||||
None,
|
||||
sms_client.clone(),
|
||||
apollo_client.clone(),
|
||||
insight_dao.clone(),
|
||||
exif_dao.clone(),
|
||||
daily_summary_dao.clone(),
|
||||
|
||||
Reference in New Issue
Block a user