Spaces:
Sleeping
Sleeping
Commit
·
3cdf7eb
1
Parent(s):
ab0d1cf
3.70
Browse files
app.py
CHANGED
|
@@ -478,7 +478,8 @@ class ProcessingUI:
|
|
| 478 |
unsafe_allow_html=True
|
| 479 |
)
|
| 480 |
self.progress_bar = st.progress(0)
|
| 481 |
-
|
|
|
|
| 482 |
# Create tabs for different views
|
| 483 |
tab1, tab2, tab3, tab4 = st.tabs([
|
| 484 |
"📊 Основные метрики",
|
|
@@ -684,7 +685,7 @@ class ProcessingUI:
|
|
| 684 |
stats = st.session_state.processing_stats
|
| 685 |
|
| 686 |
# Processing speed chart
|
| 687 |
-
speeds = stats['processing_speed'][-
|
| 688 |
fig_speed = go.Figure(data=go.Scatter(y=speeds, mode='lines'))
|
| 689 |
fig_speed.update_layout(title='Processing Speed Over Time')
|
| 690 |
self.speed_chart.plotly_chart(fig_speed, use_container_width=True)
|
|
@@ -695,6 +696,7 @@ class ProcessingUI:
|
|
| 695 |
"""Update progress bar and elapsed time"""
|
| 696 |
progress = current / total
|
| 697 |
self.progress_bar.progress(progress)
|
|
|
|
| 698 |
|
| 699 |
# Update elapsed time
|
| 700 |
elapsed = time.time() - st.session_state.processing_stats['start_time']
|
|
@@ -969,14 +971,15 @@ def process_file(uploaded_file, model_choice, translation_method=None):
|
|
| 969 |
|
| 970 |
|
| 971 |
# Show events in real-time
|
| 972 |
-
if event_type != "Нет":
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
|
| 977 |
-
|
| 978 |
|
| 979 |
#Calculate processing speed (items per second)
|
|
|
|
| 980 |
time_delta = current_time - last_update_time
|
| 981 |
if time_delta > 0:
|
| 982 |
processing_speed = 1 / time_delta # items per second
|
|
@@ -988,29 +991,34 @@ def process_file(uploaded_file, model_choice, translation_method=None):
|
|
| 988 |
|
| 989 |
|
| 990 |
# Handle negative sentiment
|
|
|
|
| 991 |
if sentiment == "Negative":
|
| 992 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 993 |
impact, reasoning = estimate_impact(
|
| 994 |
-
|
| 995 |
-
|
| 996 |
-
|
| 997 |
)
|
|
|
|
| 998 |
except Exception as e:
|
| 999 |
impact = "Неопределенный эффект"
|
| 1000 |
reasoning = "Error in impact estimation"
|
| 1001 |
-
|
| 1002 |
-
st.warning("Лимит запросов исчерпался. Иду на fallback.")
|
| 1003 |
|
| 1004 |
df.at[idx, 'Impact'] = impact
|
| 1005 |
df.at[idx, 'Reasoning'] = reasoning
|
| 1006 |
|
| 1007 |
# Show negative alert in real-time
|
| 1008 |
-
ui.show_negative(
|
| 1009 |
-
|
| 1010 |
-
|
| 1011 |
-
|
| 1012 |
-
|
| 1013 |
-
)
|
| 1014 |
|
| 1015 |
processed_rows_df = pd.concat([processed_rows_df, df.iloc[[idx]]], ignore_index=True)
|
| 1016 |
|
|
@@ -1186,41 +1194,85 @@ def init_langchain_llm(model_choice):
|
|
| 1186 |
|
| 1187 |
|
| 1188 |
def estimate_impact(llm, news_text, entity):
|
| 1189 |
-
template = """
|
| 1190 |
-
Analyze the following news piece about the entity "{entity}" and estimate its monetary impact in Russian rubles for this entity in the next 6 months.
|
| 1191 |
-
|
| 1192 |
-
If precise monetary estimate is not possible, categorize the impact as one of the following:
|
| 1193 |
-
1. "Значительный риск убытков"
|
| 1194 |
-
2. "Умеренный риск убытков"
|
| 1195 |
-
3. "Незначительный риск убытков"
|
| 1196 |
-
4. "Вероятность прибыли"
|
| 1197 |
-
5. "Неопределенный эффект"
|
| 1198 |
-
|
| 1199 |
-
Provide brief reasoning (maximum 100 words).
|
| 1200 |
-
|
| 1201 |
-
News: {news}
|
| 1202 |
-
|
| 1203 |
-
Your response should be in the following format:
|
| 1204 |
-
Impact: [Your estimate or category]
|
| 1205 |
-
Reasoning: [Your reasoning]
|
| 1206 |
"""
|
| 1207 |
-
|
| 1208 |
-
|
| 1209 |
-
|
| 1210 |
-
|
| 1211 |
impact = "Неопределенный эффект"
|
| 1212 |
reasoning = "Не удалось получить обоснование"
|
| 1213 |
|
| 1214 |
-
# Extract content from response
|
| 1215 |
-
response_text = response.content if hasattr(response, 'content') else str(response)
|
| 1216 |
-
|
| 1217 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1218 |
if "Impact:" in response_text and "Reasoning:" in response_text:
|
| 1219 |
-
|
| 1220 |
-
|
| 1221 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1222 |
except Exception as e:
|
| 1223 |
-
st.
|
|
|
|
|
|
|
| 1224 |
|
| 1225 |
return impact, reasoning
|
| 1226 |
|
|
@@ -1412,7 +1464,7 @@ def main():
|
|
| 1412 |
st.set_page_config(layout="wide")
|
| 1413 |
|
| 1414 |
with st.sidebar:
|
| 1415 |
-
st.title("::: AI-анализ мониторинга новостей (v.3.
|
| 1416 |
st.subheader("по материалам СКАН-ИНТЕРФАКС")
|
| 1417 |
|
| 1418 |
model_choice = st.radio(
|
|
|
|
| 478 |
unsafe_allow_html=True
|
| 479 |
)
|
| 480 |
self.progress_bar = st.progress(0)
|
| 481 |
+
self.status = st.empty()
|
| 482 |
+
|
| 483 |
# Create tabs for different views
|
| 484 |
tab1, tab2, tab3, tab4 = st.tabs([
|
| 485 |
"📊 Основные метрики",
|
|
|
|
| 685 |
stats = st.session_state.processing_stats
|
| 686 |
|
| 687 |
# Processing speed chart
|
| 688 |
+
speeds = stats['processing_speed'][-1:] # Last 1 measurement
|
| 689 |
fig_speed = go.Figure(data=go.Scatter(y=speeds, mode='lines'))
|
| 690 |
fig_speed.update_layout(title='Processing Speed Over Time')
|
| 691 |
self.speed_chart.plotly_chart(fig_speed, use_container_width=True)
|
|
|
|
| 696 |
"""Update progress bar and elapsed time"""
|
| 697 |
progress = current / total
|
| 698 |
self.progress_bar.progress(progress)
|
| 699 |
+
self.status.text(f"Обрабатываем {current} из {total} сообщений...")
|
| 700 |
|
| 701 |
# Update elapsed time
|
| 702 |
elapsed = time.time() - st.session_state.processing_stats['start_time']
|
|
|
|
| 971 |
|
| 972 |
|
| 973 |
# Show events in real-time
|
| 974 |
+
#if event_type != "Нет":
|
| 975 |
+
# ui.show_event(
|
| 976 |
+
# row['Объект'],
|
| 977 |
+
# event_type,
|
| 978 |
+
# row['Заголовок']
|
| 979 |
+
# )
|
| 980 |
|
| 981 |
#Calculate processing speed (items per second)
|
| 982 |
+
current_time = time.time()
|
| 983 |
time_delta = current_time - last_update_time
|
| 984 |
if time_delta > 0:
|
| 985 |
processing_speed = 1 / time_delta # items per second
|
|
|
|
| 991 |
|
| 992 |
|
| 993 |
# Handle negative sentiment
|
| 994 |
+
|
| 995 |
if sentiment == "Negative":
|
| 996 |
try:
|
| 997 |
+
# Initialize Groq LLM if not already done
|
| 998 |
+
if 'groq_llm' not in locals():
|
| 999 |
+
groq_llm = ensure_groq_llm()
|
| 1000 |
+
|
| 1001 |
impact, reasoning = estimate_impact(
|
| 1002 |
+
groq_llm if groq_llm is not None else llm,
|
| 1003 |
+
translated_text,
|
| 1004 |
+
row['Объект']
|
| 1005 |
)
|
| 1006 |
+
|
| 1007 |
except Exception as e:
|
| 1008 |
impact = "Неопределенный эффект"
|
| 1009 |
reasoning = "Error in impact estimation"
|
| 1010 |
+
st.warning(f"Impact estimation error: {str(e)}")
|
|
|
|
| 1011 |
|
| 1012 |
df.at[idx, 'Impact'] = impact
|
| 1013 |
df.at[idx, 'Reasoning'] = reasoning
|
| 1014 |
|
| 1015 |
# Show negative alert in real-time
|
| 1016 |
+
#ui.show_negative(
|
| 1017 |
+
# row['Объект'],
|
| 1018 |
+
# row['Заголовок'],
|
| 1019 |
+
# reasoning,
|
| 1020 |
+
# impact
|
| 1021 |
+
#)
|
| 1022 |
|
| 1023 |
processed_rows_df = pd.concat([processed_rows_df, df.iloc[[idx]]], ignore_index=True)
|
| 1024 |
|
|
|
|
| 1194 |
|
| 1195 |
|
| 1196 |
def estimate_impact(llm, news_text, entity):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1197 |
"""
|
| 1198 |
+
Estimate impact using Groq LLM regardless of the main model choice.
|
| 1199 |
+
Falls back to the provided LLM if Groq initialization fails.
|
| 1200 |
+
"""
|
| 1201 |
+
# Initialize default return values
|
| 1202 |
impact = "Неопределенный эффект"
|
| 1203 |
reasoning = "Не удалось получить обоснование"
|
| 1204 |
|
|
|
|
|
|
|
|
|
|
| 1205 |
try:
|
| 1206 |
+
# Always try to use Groq first
|
| 1207 |
+
groq_llm = ensure_groq_llm()
|
| 1208 |
+
working_llm = groq_llm if groq_llm is not None else llm
|
| 1209 |
+
|
| 1210 |
+
template = """
|
| 1211 |
+
You are a financial analyst. Analyze this news piece about {entity} and assess its potential impact.
|
| 1212 |
+
|
| 1213 |
+
News: {news}
|
| 1214 |
+
|
| 1215 |
+
Classify the impact into one of these categories:
|
| 1216 |
+
1. "Значительный риск убытков" (Significant loss risk)
|
| 1217 |
+
2. "Умеренный риск убытков" (Moderate loss risk)
|
| 1218 |
+
3. "Незначительный риск убытков" (Minor loss risk)
|
| 1219 |
+
4. "Вероятность прибыли" (Potential profit)
|
| 1220 |
+
5. "Неопределенный эффект" (Uncertain effect)
|
| 1221 |
+
|
| 1222 |
+
Provide a brief, fact-based reasoning for your assessment.
|
| 1223 |
+
|
| 1224 |
+
Format your response exactly as:
|
| 1225 |
+
Impact: [category]
|
| 1226 |
+
Reasoning: [explanation in 2-3 sentences]
|
| 1227 |
+
"""
|
| 1228 |
+
|
| 1229 |
+
prompt = PromptTemplate(template=template, input_variables=["entity", "news"])
|
| 1230 |
+
chain = prompt | working_llm
|
| 1231 |
+
|
| 1232 |
+
# Handle both dictionary and direct string inputs
|
| 1233 |
+
if isinstance(news_text, dict):
|
| 1234 |
+
response = chain.invoke(news_text)
|
| 1235 |
+
else:
|
| 1236 |
+
response = chain.invoke({"entity": entity, "news": news_text})
|
| 1237 |
+
|
| 1238 |
+
# Extract content from response
|
| 1239 |
+
response_text = response.content if hasattr(response, 'content') else str(response)
|
| 1240 |
+
|
| 1241 |
if "Impact:" in response_text and "Reasoning:" in response_text:
|
| 1242 |
+
try:
|
| 1243 |
+
impact_part, reasoning_part = response_text.split("Reasoning:")
|
| 1244 |
+
impact_temp = impact_part.split("Impact:")[1].strip()
|
| 1245 |
+
|
| 1246 |
+
# Validate impact category
|
| 1247 |
+
valid_impacts = [
|
| 1248 |
+
"Значительный риск убытков",
|
| 1249 |
+
"Умеренный риск убытков",
|
| 1250 |
+
"Незначительный риск убытков",
|
| 1251 |
+
"Вероятность прибыли",
|
| 1252 |
+
"Неопределенный эффект"
|
| 1253 |
+
]
|
| 1254 |
+
|
| 1255 |
+
# Use fuzzy matching to handle slight variations
|
| 1256 |
+
best_match = None
|
| 1257 |
+
best_score = 0
|
| 1258 |
+
impact_temp_lower = impact_temp.lower()
|
| 1259 |
+
|
| 1260 |
+
for valid_impact in valid_impacts:
|
| 1261 |
+
score = fuzz.ratio(impact_temp_lower, valid_impact.lower())
|
| 1262 |
+
if score > best_score and score > 80: # 80% similarity threshold
|
| 1263 |
+
best_score = score
|
| 1264 |
+
best_match = valid_impact
|
| 1265 |
+
|
| 1266 |
+
impact = best_match if best_match else "Неопределенный эффект"
|
| 1267 |
+
reasoning = reasoning_part.strip()
|
| 1268 |
+
|
| 1269 |
+
except Exception as e:
|
| 1270 |
+
st.warning(f"Error parsing impact response: {str(e)}")
|
| 1271 |
+
|
| 1272 |
except Exception as e:
|
| 1273 |
+
st.warning(f"Error in impact estimation: {str(e)}")
|
| 1274 |
+
if 'rate limit' in str(e).lower():
|
| 1275 |
+
st.warning("Rate limit reached. Using fallback model.")
|
| 1276 |
|
| 1277 |
return impact, reasoning
|
| 1278 |
|
|
|
|
| 1464 |
st.set_page_config(layout="wide")
|
| 1465 |
|
| 1466 |
with st.sidebar:
|
| 1467 |
+
st.title("::: AI-анализ мониторинга новостей (v.3.70):::")
|
| 1468 |
st.subheader("по материалам СКАН-ИНТЕРФАКС")
|
| 1469 |
|
| 1470 |
model_choice = st.radio(
|