Upload 59 files
Browse files- app/api/routes/timeline.py +6 -2
- app/models/entity.py +6 -0
- app/services/nlp/entity_extractor.py +12 -5
app/api/routes/timeline.py
CHANGED
|
@@ -73,13 +73,15 @@ async def get_timeline(
|
|
| 73 |
}
|
| 74 |
|
| 75 |
for e in entities:
|
|
|
|
|
|
|
| 76 |
events.append(TimelineEvent(
|
| 77 |
id=e.id,
|
| 78 |
type="entity",
|
| 79 |
entity_type=e.type,
|
| 80 |
name=e.name,
|
| 81 |
description=e.description[:100] if e.description else None,
|
| 82 |
-
date=
|
| 83 |
icon=icon_map.get(e.type, "📄")
|
| 84 |
))
|
| 85 |
|
|
@@ -93,12 +95,14 @@ async def get_timeline(
|
|
| 93 |
target = db.query(Entity).filter(Entity.id == r.target_id).first()
|
| 94 |
|
| 95 |
if source and target:
|
|
|
|
|
|
|
| 96 |
events.append(TimelineEvent(
|
| 97 |
id=r.id,
|
| 98 |
type="relationship",
|
| 99 |
name=f"{source.name} → {target.name}",
|
| 100 |
description=r.type,
|
| 101 |
-
date=
|
| 102 |
icon="🔗"
|
| 103 |
))
|
| 104 |
|
|
|
|
| 73 |
}
|
| 74 |
|
| 75 |
for e in entities:
|
| 76 |
+
# Prefer event_date over created_at
|
| 77 |
+
date = e.event_date if e.event_date else e.created_at
|
| 78 |
events.append(TimelineEvent(
|
| 79 |
id=e.id,
|
| 80 |
type="entity",
|
| 81 |
entity_type=e.type,
|
| 82 |
name=e.name,
|
| 83 |
description=e.description[:100] if e.description else None,
|
| 84 |
+
date=date.isoformat() if date else datetime.now().isoformat(),
|
| 85 |
icon=icon_map.get(e.type, "📄")
|
| 86 |
))
|
| 87 |
|
|
|
|
| 95 |
target = db.query(Entity).filter(Entity.id == r.target_id).first()
|
| 96 |
|
| 97 |
if source and target:
|
| 98 |
+
# Prefer event_date over created_at
|
| 99 |
+
date = r.event_date if r.event_date else r.created_at
|
| 100 |
events.append(TimelineEvent(
|
| 101 |
id=r.id,
|
| 102 |
type="relationship",
|
| 103 |
name=f"{source.name} → {target.name}",
|
| 104 |
description=r.type,
|
| 105 |
+
date=date.isoformat() if date else datetime.now().isoformat(),
|
| 106 |
icon="🔗"
|
| 107 |
))
|
| 108 |
|
app/models/entity.py
CHANGED
|
@@ -30,6 +30,9 @@ class Entity(Base):
|
|
| 30 |
latitude = Column(Float, nullable=True)
|
| 31 |
longitude = Column(Float, nullable=True)
|
| 32 |
|
|
|
|
|
|
|
|
|
|
| 33 |
# Fonte do dado
|
| 34 |
source = Column(String(100), nullable=True) # wikipedia, newsapi, manual, etc
|
| 35 |
source_url = Column(Text, nullable=True)
|
|
@@ -65,6 +68,9 @@ class Relationship(Base):
|
|
| 65 |
properties = Column(JSON, default=dict)
|
| 66 |
confidence = Column(Float, default=1.0) # 0-1, quão certo estamos dessa conexão
|
| 67 |
|
|
|
|
|
|
|
|
|
|
| 68 |
# Fonte
|
| 69 |
source = Column(String(100), nullable=True)
|
| 70 |
|
|
|
|
| 30 |
latitude = Column(Float, nullable=True)
|
| 31 |
longitude = Column(Float, nullable=True)
|
| 32 |
|
| 33 |
+
# Data histórica do evento/entidade (quando aconteceu, não quando foi adicionado)
|
| 34 |
+
event_date = Column(DateTime, nullable=True)
|
| 35 |
+
|
| 36 |
# Fonte do dado
|
| 37 |
source = Column(String(100), nullable=True) # wikipedia, newsapi, manual, etc
|
| 38 |
source_url = Column(Text, nullable=True)
|
|
|
|
| 68 |
properties = Column(JSON, default=dict)
|
| 69 |
confidence = Column(Float, default=1.0) # 0-1, quão certo estamos dessa conexão
|
| 70 |
|
| 71 |
+
# Data histórica do relacionamento (quando aconteceu)
|
| 72 |
+
event_date = Column(DateTime, nullable=True)
|
| 73 |
+
|
| 74 |
# Fonte
|
| 75 |
source = Column(String(100), nullable=True)
|
| 76 |
|
app/services/nlp/entity_extractor.py
CHANGED
|
@@ -21,6 +21,7 @@ class ExtractedEntity:
|
|
| 21 |
description: Optional[str] = None
|
| 22 |
latitude: Optional[float] = None
|
| 23 |
longitude: Optional[float] = None
|
|
|
|
| 24 |
|
| 25 |
|
| 26 |
@dataclass
|
|
@@ -30,6 +31,7 @@ class ExtractedRelationship:
|
|
| 30 |
target: str
|
| 31 |
relationship_type: str
|
| 32 |
context: Optional[str] = None
|
|
|
|
| 33 |
|
| 34 |
|
| 35 |
@dataclass
|
|
@@ -62,6 +64,7 @@ Analise o texto fornecido e extraia TODAS as entidades, relacionamentos e evento
|
|
| 62 |
4. Para LOCAIS: seja específico (cidade, país, endereço)
|
| 63 |
5. Identifique RELACIONAMENTOS entre entidades (quem trabalha onde, quem conhece quem, etc.)
|
| 64 |
6. Identifique EVENTOS mencionados (reuniões, anúncios, eleições, etc.)
|
|
|
|
| 65 |
|
| 66 |
## Formato de resposta (JSON válido):
|
| 67 |
```json
|
|
@@ -72,7 +75,8 @@ Analise o texto fornecido e extraia TODAS as entidades, relacionamentos e evento
|
|
| 72 |
"type": "person|organization|location|event",
|
| 73 |
"role": "cargo ou função (opcional)",
|
| 74 |
"aliases": ["apelidos", "siglas"],
|
| 75 |
-
"description": "breve descrição se relevante"
|
|
|
|
| 76 |
}}
|
| 77 |
],
|
| 78 |
"relationships": [
|
|
@@ -80,14 +84,15 @@ Analise o texto fornecido e extraia TODAS as entidades, relacionamentos e evento
|
|
| 80 |
"source": "Nome da Entidade 1",
|
| 81 |
"target": "Nome da Entidade 2",
|
| 82 |
"relationship_type": "tipo de relação (trabalha em, preside, fundou, reuniu-se com, etc.)",
|
| 83 |
-
"context": "contexto da relação"
|
|
|
|
| 84 |
}}
|
| 85 |
],
|
| 86 |
"events": [
|
| 87 |
{{
|
| 88 |
"description": "O que aconteceu",
|
| 89 |
"event_type": "meeting|announcement|election|crime|etc",
|
| 90 |
-
"date": "
|
| 91 |
"location": "local se mencionado",
|
| 92 |
"participants": ["lista de participantes"]
|
| 93 |
}}
|
|
@@ -205,7 +210,8 @@ class EntityExtractor:
|
|
| 205 |
type=e.get("type", "unknown"),
|
| 206 |
role=e.get("role"),
|
| 207 |
aliases=e.get("aliases", []),
|
| 208 |
-
description=e.get("description")
|
|
|
|
| 209 |
))
|
| 210 |
|
| 211 |
# Parse relationships
|
|
@@ -215,7 +221,8 @@ class EntityExtractor:
|
|
| 215 |
source=r.get("source", ""),
|
| 216 |
target=r.get("target", ""),
|
| 217 |
relationship_type=r.get("relationship_type", "related_to"),
|
| 218 |
-
context=r.get("context")
|
|
|
|
| 219 |
))
|
| 220 |
|
| 221 |
# Parse events
|
|
|
|
| 21 |
description: Optional[str] = None
|
| 22 |
latitude: Optional[float] = None
|
| 23 |
longitude: Optional[float] = None
|
| 24 |
+
event_date: Optional[str] = None # Date in ISO format (YYYY-MM-DD)
|
| 25 |
|
| 26 |
|
| 27 |
@dataclass
|
|
|
|
| 31 |
target: str
|
| 32 |
relationship_type: str
|
| 33 |
context: Optional[str] = None
|
| 34 |
+
event_date: Optional[str] = None # Date in ISO format (YYYY-MM-DD)
|
| 35 |
|
| 36 |
|
| 37 |
@dataclass
|
|
|
|
| 64 |
4. Para LOCAIS: seja específico (cidade, país, endereço)
|
| 65 |
5. Identifique RELACIONAMENTOS entre entidades (quem trabalha onde, quem conhece quem, etc.)
|
| 66 |
6. Identifique EVENTOS mencionados (reuniões, anúncios, eleições, etc.)
|
| 67 |
+
7. EXTRAIA DATAS sempre que mencionadas (formato YYYY-MM-DD ou YYYY se só o ano)
|
| 68 |
|
| 69 |
## Formato de resposta (JSON válido):
|
| 70 |
```json
|
|
|
|
| 75 |
"type": "person|organization|location|event",
|
| 76 |
"role": "cargo ou função (opcional)",
|
| 77 |
"aliases": ["apelidos", "siglas"],
|
| 78 |
+
"description": "breve descrição se relevante",
|
| 79 |
+
"event_date": "YYYY-MM-DD ou YYYY (data relevante como nascimento, fundação, etc)"
|
| 80 |
}}
|
| 81 |
],
|
| 82 |
"relationships": [
|
|
|
|
| 84 |
"source": "Nome da Entidade 1",
|
| 85 |
"target": "Nome da Entidade 2",
|
| 86 |
"relationship_type": "tipo de relação (trabalha em, preside, fundou, reuniu-se com, etc.)",
|
| 87 |
+
"context": "contexto da relação",
|
| 88 |
+
"event_date": "YYYY-MM-DD ou YYYY (quando o relacionamento aconteceu/iniciou)"
|
| 89 |
}}
|
| 90 |
],
|
| 91 |
"events": [
|
| 92 |
{{
|
| 93 |
"description": "O que aconteceu",
|
| 94 |
"event_type": "meeting|announcement|election|crime|etc",
|
| 95 |
+
"date": "YYYY-MM-DD ou YYYY",
|
| 96 |
"location": "local se mencionado",
|
| 97 |
"participants": ["lista de participantes"]
|
| 98 |
}}
|
|
|
|
| 210 |
type=e.get("type", "unknown"),
|
| 211 |
role=e.get("role"),
|
| 212 |
aliases=e.get("aliases", []),
|
| 213 |
+
description=e.get("description"),
|
| 214 |
+
event_date=e.get("event_date")
|
| 215 |
))
|
| 216 |
|
| 217 |
# Parse relationships
|
|
|
|
| 221 |
source=r.get("source", ""),
|
| 222 |
target=r.get("target", ""),
|
| 223 |
relationship_type=r.get("relationship_type", "related_to"),
|
| 224 |
+
context=r.get("context"),
|
| 225 |
+
event_date=r.get("event_date")
|
| 226 |
))
|
| 227 |
|
| 228 |
# Parse events
|