File size: 5,937 Bytes
feeaf83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import logging
from typing import List, Dict, Any
from sqlalchemy.orm import Session
from src.database.models import VerifiedNews
from src.analysis.llm_analyzer import LLMAnalyzer
import openai
from src.config.settings import OPENAI_API_KEY

from loguru import logger
# logger = logging.getLogger(__name__)

class NewsChatEngine:
    def __init__(self):
        self.api_key = OPENAI_API_KEY
        if self.api_key:
            self.client = openai.OpenAI(api_key=self.api_key)
        else:
            self.client = None

    def get_response(self, session: Session, query: str) -> str:
        """
        Simple RAG: Find relevant news and answer based on it.
        """
        if not self.client:
            return "I'm sorry, I cannot answer questions right now as no AI API key is configured."

        # 1. Search DB for relevant keywords (Naive search for now)
        # In a real app, use Vector Search (FAISS) which is in requirements
        keywords = query.split()
        if not keywords:
            results = session.query(VerifiedNews).order_by(VerifiedNews.published_at.desc()).limit(3).all()
        else:
            # Simple keyword search with multiple words
            filters = [VerifiedNews.title.contains(k) | VerifiedNews.content.contains(k) for k in keywords[:3]]
            from sqlalchemy import or_
            results = session.query(VerifiedNews).filter(or_(*filters)).limit(5).all()

        if not results:
            # Fallback to general latest news
            results = session.query(VerifiedNews).order_by(VerifiedNews.published_at.desc()).limit(3).all()

        context = "\n---\n".join([
            f"Title: {n.title}\nSummary: {n.summary_bullets}\nWhy it matters: {n.why_it_matters}\nWho is affected: {n.who_is_affected}"
            for n in results
        ])

        system_prompt = """
        You are a Conversational News Intelligence Assistant.
        Answer user questions ONLY based on the provided news context.
        Always cite the source/title.

        CRITICAL SAFETY RULES:
        1. NEVER claim absolute accuracy.
        2. NO hallucinated facts. If information is missing, say so politely.
        3. Maintain a neutral, factual tone.
        4. If the information is not in the context, state "Based on current data, I do not have information on this."
        """

        user_prompt = f"User Question: {query}\n\nContext:\n{context}"

        try:
            # Check if API key is a placeholder
            if not self.api_key or self.api_key.startswith("your_"):
                return self._mock_response(query, results)

            response = self.client.chat.completions.create(
                model="gpt-4o-mini",
                messages=[
                    {"role": "system", "content": system_prompt},
                    {"role": "user", "content": user_prompt}
                ],
                temperature=0.4
            )
            return response.choices[0].message.content
        except Exception as e:
            logger.error(f"Chat failed: {e}")
            return self._mock_response(query, results)

    def chat_with_article(self, session: Session, article_id: int, query: str) -> str:
        """
        Focused chat about a single article.
        """
        if not self.client:
            return "I'm sorry, I cannot answer questions right now as no AI API key is configured."

        article = session.query(VerifiedNews).filter(VerifiedNews.id == article_id).first()
        if not article:
            return "I couldn't find the article you're referring to."

        context = f"""
        Title: {article.title}
        Summary: {article.summary_bullets}
        Why it matters: {article.why_it_matters}
        Who is affected: {article.who_is_affected}
        Full Content: {article.content[:4000]}
        """

        system_prompt = """
        You are an AI News Analyst. 
        Answer the user's question explicitly based on the provided article context.
        If the information is not present, say so.
        Be concise, professional, and helpful.
        """

        user_prompt = f"Article Context:\n{context}\n\nUser Question: {query}"

        try:
            # Check for mock mode
            if not self.api_key or self.api_key.startswith("your_"):
                return f"Based on the article '{article.title}', here is a simulated response to your question: '{query}'. (Real-time AI is in mock mode)."

            response = self.client.chat.completions.create(
                model="gpt-4o-mini",
                messages=[
                    {"role": "system", "content": system_prompt},
                    {"role": "user", "content": user_prompt}
                ],
                temperature=0.3
            )
            return response.choices[0].message.content
        except Exception as e:
            logger.error(f"Article chat failed: {e}")
            if "quota" in str(e).lower() or "429" in str(e):
                return "The AI Analysis node has reached its usage limit for today. Please try again tomorrow or upgrade your plan."
            return f"I encountered an error while processing your request. Please try again later."

    def _mock_response(self, query: str, results: List[VerifiedNews]) -> str:
        """
        Fallback response using keyword matching and context.
        """
        if not results:
            return "I couldn't find any news related to your query. Try asking something else!"
        
        response = f"I found several relevant stories in our system:\n\n"
        for n in results:
            response += f"• {n.title} (Category: {n.category})\n"
            response += f"  - Impact: {n.why_it_matters}\n"
            response += f"  - Affected: {n.who_is_affected}\n\n"
        
        response += "Note: Real-time conversational analysis is currently in mock mode due to API configuration."
        return response