Spaces:
Running
Running
Commit
·
cf42361
1
Parent(s):
7a99adf
3.73
Browse files
app.py
CHANGED
@@ -559,27 +559,29 @@ class ProcessingUI:
|
|
559 |
key="event_filter_key"
|
560 |
)
|
561 |
|
562 |
-
|
563 |
-
if 'timeline_container' not in st.session_state:
|
564 |
-
st.session_state.timeline_container = st.container()
|
565 |
|
566 |
def _update_events_view(self, row, event_type):
|
567 |
"""Update events timeline"""
|
568 |
if event_type != 'Нет':
|
569 |
event_html = f"""
|
570 |
-
<div class='timeline-item'
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
</
|
|
|
|
|
|
|
579 |
</div>
|
580 |
"""
|
581 |
with self.timeline_container:
|
582 |
-
st.markdown(event_html, unsafe_allow_html=True)
|
|
|
583 |
def setup_analytics_tab(self):
|
584 |
"""Setup the analytics display"""
|
585 |
# Create containers for analytics
|
@@ -1296,86 +1298,87 @@ def init_langchain_llm(model_choice):
|
|
1296 |
|
1297 |
def estimate_impact(llm, news_text, entity):
|
1298 |
"""
|
1299 |
-
Estimate impact using Groq LLM
|
1300 |
-
Falls back to the provided LLM if Groq initialization fails.
|
1301 |
"""
|
1302 |
-
# Initialize default return values
|
1303 |
-
impact = "Неопределенный эффект"
|
1304 |
-
reasoning = "Не удалось получить обоснование"
|
1305 |
-
|
1306 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1307 |
# Always try to use Groq first
|
1308 |
-
|
1309 |
-
working_llm = groq_llm if groq_llm is not None else llm
|
1310 |
|
1311 |
template = """
|
1312 |
-
You are a financial analyst
|
1313 |
|
1314 |
-
|
|
|
1315 |
|
1316 |
-
|
1317 |
-
1. "Значительный риск убытков"
|
1318 |
-
2. "Умеренный риск убытков"
|
1319 |
-
3. "Незначительный риск убытков"
|
1320 |
-
4. "Вероятность прибыли"
|
1321 |
-
5. "Неопределенный эффект"
|
1322 |
|
1323 |
-
|
1324 |
-
|
1325 |
-
|
1326 |
-
Impact: [category]
|
1327 |
-
Reasoning: [explanation in 2-3 sentences]
|
1328 |
"""
|
1329 |
|
1330 |
prompt = PromptTemplate(template=template, input_variables=["entity", "news"])
|
1331 |
chain = prompt | working_llm
|
1332 |
|
1333 |
-
#
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
|
1339 |
-
#
|
1340 |
response_text = response.content if hasattr(response, 'content') else str(response)
|
1341 |
|
|
|
|
|
|
|
|
|
1342 |
if "Impact:" in response_text and "Reasoning:" in response_text:
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
except Exception as e:
|
1371 |
-
st.warning(f"Error parsing impact response: {str(e)}")
|
1372 |
-
|
1373 |
except Exception as e:
|
1374 |
-
st.warning(f"
|
1375 |
if 'rate limit' in str(e).lower():
|
1376 |
-
st.warning("Rate limit reached. Using fallback
|
1377 |
-
|
1378 |
-
return impact, reasoning
|
1379 |
|
1380 |
def format_elapsed_time(seconds):
|
1381 |
hours, remainder = divmod(int(seconds), 3600)
|
@@ -1565,7 +1568,7 @@ def main():
|
|
1565 |
st.set_page_config(layout="wide")
|
1566 |
|
1567 |
with st.sidebar:
|
1568 |
-
st.title("::: AI-анализ мониторинга новостей (v.3.
|
1569 |
st.subheader("по материалам СКАН-ИНТЕРФАКС")
|
1570 |
|
1571 |
model_choice = st.radio(
|
|
|
559 |
key="event_filter_key"
|
560 |
)
|
561 |
|
562 |
+
self.timeline_container = st.container()
|
|
|
|
|
563 |
|
564 |
def _update_events_view(self, row, event_type):
|
565 |
"""Update events timeline"""
|
566 |
if event_type != 'Нет':
|
567 |
event_html = f"""
|
568 |
+
<div class='timeline-item' style='
|
569 |
+
border-left: 4px solid #2196F3;
|
570 |
+
margin: 10px 0;
|
571 |
+
padding: 10px;
|
572 |
+
background: #f5f5f5;
|
573 |
+
border-radius: 4px;
|
574 |
+
'>
|
575 |
+
<h4 style='color: #2196F3; margin: 0;'>{event_type}</h4>
|
576 |
+
<p><strong>{row['Объект']}</strong></p>
|
577 |
+
<p>{row['Заголовок']}</p>
|
578 |
+
<p style='font-size: 0.9em;'>{row['Выдержки из текста']}</p>
|
579 |
+
<small style='color: #666;'>{datetime.now().strftime('%H:%M:%S')}</small>
|
580 |
</div>
|
581 |
"""
|
582 |
with self.timeline_container:
|
583 |
+
st.markdown(event_html, unsafe_allow_html=True)
|
584 |
+
|
585 |
def setup_analytics_tab(self):
|
586 |
"""Setup the analytics display"""
|
587 |
# Create containers for analytics
|
|
|
1298 |
|
1299 |
def estimate_impact(llm, news_text, entity):
|
1300 |
"""
|
1301 |
+
Estimate impact using Groq LLM with improved error handling and validation.
|
|
|
1302 |
"""
|
|
|
|
|
|
|
|
|
1303 |
try:
|
1304 |
+
# Input validation
|
1305 |
+
if not news_text or not entity:
|
1306 |
+
return "Неопределенный эффект", "Недостаточно данных для анализа"
|
1307 |
+
|
1308 |
+
# Clean up inputs
|
1309 |
+
news_text = str(news_text).strip()
|
1310 |
+
entity = str(entity).strip()
|
1311 |
+
|
1312 |
# Always try to use Groq first
|
1313 |
+
working_llm = ensure_groq_llm() if 'groq_key' in st.secrets else llm
|
|
|
1314 |
|
1315 |
template = """
|
1316 |
+
You are a financial analyst tasked with assessing the impact of news on a company.
|
1317 |
|
1318 |
+
Company: {entity}
|
1319 |
+
News Text: {news}
|
1320 |
|
1321 |
+
Based on the news content, strictly classify the potential impact into ONE of these categories:
|
1322 |
+
1. "Значительный риск убытков" - For severe negative events like bankruptcy, major legal issues, significant market loss
|
1323 |
+
2. "Умеренный риск убытков" - For moderate negative events like minor legal issues, temporary setbacks
|
1324 |
+
3. "Незначительный риск убытков" - For minor negative events with limited impact
|
1325 |
+
4. "Вероятность прибыли" - For positive events that could lead to profit or growth
|
1326 |
+
5. "Неопределенный эффект" - Only if impact cannot be determined from the information
|
1327 |
|
1328 |
+
FORMAT YOUR RESPONSE EXACTLY AS:
|
1329 |
+
Impact: [category name exactly as shown above]
|
1330 |
+
Reasoning: [2-3 concise sentences explaining your choice]
|
|
|
|
|
1331 |
"""
|
1332 |
|
1333 |
prompt = PromptTemplate(template=template, input_variables=["entity", "news"])
|
1334 |
chain = prompt | working_llm
|
1335 |
|
1336 |
+
# Make the API call
|
1337 |
+
response = chain.invoke({
|
1338 |
+
"entity": entity,
|
1339 |
+
"news": news_text
|
1340 |
+
})
|
1341 |
|
1342 |
+
# Parse response
|
1343 |
response_text = response.content if hasattr(response, 'content') else str(response)
|
1344 |
|
1345 |
+
# Extract impact and reasoning
|
1346 |
+
impact = "Неопределенный эффект" # Default
|
1347 |
+
reasoning = "Не удалось определить влияние" # Default
|
1348 |
+
|
1349 |
if "Impact:" in response_text and "Reasoning:" in response_text:
|
1350 |
+
parts = response_text.split("Reasoning:")
|
1351 |
+
impact_part = parts[0].split("Impact:")[1].strip()
|
1352 |
+
reasoning = parts[1].strip()
|
1353 |
+
|
1354 |
+
# Validate impact category with fuzzy matching
|
1355 |
+
valid_impacts = [
|
1356 |
+
"Значительный риск убытков",
|
1357 |
+
"Умеренный риск убытков",
|
1358 |
+
"Незначительный риск убытков",
|
1359 |
+
"Вероятность прибыли",
|
1360 |
+
"Неопределенный эффект"
|
1361 |
+
]
|
1362 |
+
|
1363 |
+
# Use fuzzy matching
|
1364 |
+
best_match = None
|
1365 |
+
best_score = 0
|
1366 |
+
for valid_impact in valid_impacts:
|
1367 |
+
score = fuzz.ratio(impact_part.lower(), valid_impact.lower())
|
1368 |
+
if score > best_score and score > 80: # 80% similarity threshold
|
1369 |
+
best_score = score
|
1370 |
+
best_match = valid_impact
|
1371 |
+
|
1372 |
+
if best_match:
|
1373 |
+
impact = best_match
|
1374 |
+
|
1375 |
+
return impact, reasoning
|
1376 |
+
|
|
|
|
|
|
|
1377 |
except Exception as e:
|
1378 |
+
st.warning(f"Impact estimation error: {str(e)}")
|
1379 |
if 'rate limit' in str(e).lower():
|
1380 |
+
st.warning("Rate limit reached. Using fallback analysis.")
|
1381 |
+
return "Неопределенный эффект", "Ошибка при анализе влияния"
|
|
|
1382 |
|
1383 |
def format_elapsed_time(seconds):
|
1384 |
hours, remainder = divmod(int(seconds), 3600)
|
|
|
1568 |
st.set_page_config(layout="wide")
|
1569 |
|
1570 |
with st.sidebar:
|
1571 |
+
st.title("::: AI-анализ мониторинга новостей (v.3.73):::")
|
1572 |
st.subheader("по материалам СКАН-ИНТЕРФАКС")
|
1573 |
|
1574 |
model_choice = st.radio(
|