landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
ObservationStore - Sparar och hämtar observationer
|
||||
"""
|
||||
import sqlite3
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
DB_PATH = "/home/bernt/.openclaw/workspace/rivp-pilot-1/rivp.db"
|
||||
RAW_DIR = Path("/home/bernt/.openclaw/workspace/life-weather/raw")
|
||||
RAW_DIR.mkdir(exist_ok=True)
|
||||
|
||||
class ObservationStore:
|
||||
def __init__(self, db_path=DB_PATH):
|
||||
self.db_path = db_path
|
||||
self._init_db()
|
||||
|
||||
def _init_db(self):
|
||||
"""Initiera databasen"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
|
||||
# Huvudtabell för väderobservationer
|
||||
c.execute('''
|
||||
CREATE TABLE IF NOT EXISTS weather_observations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
road_id INTEGER,
|
||||
station_id TEXT,
|
||||
observation_type TEXT,
|
||||
value REAL,
|
||||
unit TEXT,
|
||||
timestamp TEXT,
|
||||
raw_data TEXT,
|
||||
source TEXT,
|
||||
created_at TEXT
|
||||
)
|
||||
''')
|
||||
|
||||
# Index för snabbare sökning
|
||||
c.execute('''
|
||||
CREATE INDEX IF NOT EXISTS idx_weather_road
|
||||
ON weather_observations(road_id, timestamp)
|
||||
''')
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def save_raw_data(self, weather_data, filename=None):
|
||||
"""Spara rådata oförändrad"""
|
||||
if filename is None:
|
||||
filename = f"weather_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
||||
|
||||
filepath = RAW_DIR / filename
|
||||
with open(filepath, 'w') as f:
|
||||
json.dump(weather_data, f, indent=2)
|
||||
|
||||
return filepath
|
||||
|
||||
def save_observation(self, road_id, observation_type, value, unit, timestamp, raw_data, source="smhi"):
|
||||
"""Spara normaliserad observation"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
|
||||
# Idempotent - kolla om observation redan finns
|
||||
c.execute('''
|
||||
SELECT id FROM weather_observations
|
||||
WHERE road_id = ? AND observation_type = ? AND timestamp = ?
|
||||
''', (road_id, observation_type, timestamp))
|
||||
|
||||
if c.fetchone():
|
||||
conn.close()
|
||||
return None # Redan sparad
|
||||
|
||||
c.execute('''
|
||||
INSERT INTO weather_observations
|
||||
(road_id, station_id, observation_type, value, unit, timestamp, raw_data, source, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', (
|
||||
road_id,
|
||||
"97530", # Uppsala station
|
||||
observation_type,
|
||||
value,
|
||||
unit,
|
||||
timestamp,
|
||||
json.dumps(raw_data),
|
||||
source,
|
||||
datetime.now().isoformat()
|
||||
))
|
||||
|
||||
obs_id = c.lastrowid
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return obs_id
|
||||
|
||||
def get_latest_for_road(self, road_id, observation_type=None):
|
||||
"""Hämta senaste observation för väg"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
|
||||
if observation_type:
|
||||
c.execute('''
|
||||
SELECT * FROM weather_observations
|
||||
WHERE road_id = ? AND observation_type = ?
|
||||
ORDER BY timestamp DESC LIMIT 1
|
||||
''', (road_id, observation_type))
|
||||
else:
|
||||
c.execute('''
|
||||
SELECT * FROM weather_observations
|
||||
WHERE road_id = ?
|
||||
ORDER BY timestamp DESC LIMIT 1
|
||||
''', (road_id,))
|
||||
|
||||
row = c.fetchone()
|
||||
conn.close()
|
||||
|
||||
return row
|
||||
|
||||
if __name__ == "__main__":
|
||||
store = ObservationStore()
|
||||
print("ObservationStore initierad")
|
||||
print(f"Rådata sparas i: {RAW_DIR}")
|
||||
Reference in New Issue
Block a user