Update app.py
Browse files
app.py
CHANGED
@@ -200,34 +200,133 @@ def plot_historical_data(historical_data):
|
|
200 |
plt.axis('off')
|
201 |
return plt
|
202 |
|
203 |
-
def create_evolution_chart(data):
|
204 |
-
"""Create an evolution chart from data
|
205 |
try:
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
|
|
|
|
|
|
219 |
|
220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
except Exception as e:
|
222 |
print(f"Error in create_evolution_chart: {str(e)}")
|
223 |
-
#
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 |
|
230 |
-
def analyze_keyword(keyword, progress=gr.Progress()):
|
231 |
"""Main function to analyze a keyword"""
|
232 |
if not keyword or not keyword.strip():
|
233 |
return (
|
@@ -365,19 +464,37 @@ def analyze_keyword(keyword, progress=gr.Progress()):
|
|
365 |
"Visual search integration"
|
366 |
]
|
367 |
|
368 |
-
#
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
377 |
|
378 |
progress(0.8, desc="Creating visualizations...")
|
379 |
-
# Create
|
380 |
-
evolution_chart = create_evolution_chart(evolution_data)
|
381 |
|
382 |
# Generate HTML for token visualization
|
383 |
token_viz_html = generate_token_visualization_html(token_analysis, full_token_analysis)
|
@@ -397,7 +514,12 @@ def analyze_keyword(keyword, progress=gr.Progress()):
|
|
397 |
"tokenAnalysis": full_token_analysis,
|
398 |
"intentAnalysis": intent_analysis,
|
399 |
"evolutionPotential": evolution_potential,
|
400 |
-
"predictedTrends": trends
|
|
|
|
|
|
|
|
|
|
|
401 |
}
|
402 |
|
403 |
progress(1.0, desc="Analysis complete!")
|
@@ -582,7 +704,7 @@ def generate_full_analysis_html(keyword, token_analysis, intent_analysis, evolut
|
|
582 |
<div style="font-size: 12px; margin-bottom: 8px;">
|
583 |
<span style="font-weight: 500;">Origin: </span>
|
584 |
<span>{token['origin']['era']}, </span>
|
585 |
-
|
586 |
</div>
|
587 |
<div style="font-size: 12px; margin-bottom: 12px;">{token['origin']['note']}</div>
|
588 |
|
@@ -623,6 +745,11 @@ with gr.Blocks(css="footer {visibility: hidden}") as demo:
|
|
623 |
with gr.Column():
|
624 |
input_text = gr.Textbox(label="Enter keyword to analyze", placeholder="e.g. artificial intelligence")
|
625 |
|
|
|
|
|
|
|
|
|
|
|
626 |
# Add loading indicator
|
627 |
status_html = gr.HTML('<div style="color:gray;text-align:center;">Enter a keyword and click "Analyze DNA"</div>')
|
628 |
|
@@ -642,7 +769,7 @@ with gr.Blocks(css="footer {visibility: hidden}") as demo:
|
|
642 |
analysis_html = gr.HTML()
|
643 |
|
644 |
with gr.Tab("Evolution Chart"):
|
645 |
-
evolution_chart = gr.Plot()
|
646 |
|
647 |
with gr.Tab("Raw Data"):
|
648 |
json_output = gr.JSON()
|
@@ -653,7 +780,7 @@ with gr.Blocks(css="footer {visibility: hidden}") as demo:
|
|
653 |
outputs=status_html
|
654 |
).then(
|
655 |
analyze_keyword,
|
656 |
-
inputs=[input_text],
|
657 |
outputs=[token_viz_html, analysis_html, json_output, evolution_chart]
|
658 |
).then(
|
659 |
lambda: '<div style="color:green;text-align:center;">Analysis complete!</div>',
|
@@ -662,8 +789,12 @@ with gr.Blocks(css="footer {visibility: hidden}") as demo:
|
|
662 |
|
663 |
# Example buttons
|
664 |
for btn in example_btns:
|
|
|
|
|
|
|
|
|
665 |
btn.click(
|
666 |
-
|
667 |
inputs=[btn],
|
668 |
outputs=[input_text]
|
669 |
).then(
|
@@ -671,7 +802,7 @@ with gr.Blocks(css="footer {visibility: hidden}") as demo:
|
|
671 |
outputs=status_html
|
672 |
).then(
|
673 |
analyze_keyword,
|
674 |
-
inputs=[input_text],
|
675 |
outputs=[token_viz_html, analysis_html, json_output, evolution_chart]
|
676 |
).then(
|
677 |
lambda: '<div style="color:green;text-align:center;">Analysis complete!</div>',
|
|
|
200 |
plt.axis('off')
|
201 |
return plt
|
202 |
|
203 |
+
def create_evolution_chart(data, forecast_months=6, growth_scenario="Moderate"):
|
204 |
+
"""Create an interactive evolution chart from data using Plotly"""
|
205 |
try:
|
206 |
+
import plotly.graph_objects as go
|
207 |
+
from plotly.subplots import make_subplots
|
208 |
+
|
209 |
+
# Create figure
|
210 |
+
fig = make_subplots(specs=[[{"secondary_y": True}]])
|
211 |
+
|
212 |
+
# Add traces
|
213 |
+
fig.add_trace(
|
214 |
+
go.Scatter(
|
215 |
+
x=[item["month"] for item in data],
|
216 |
+
y=[item["searchVolume"] for item in data],
|
217 |
+
name="Search Volume",
|
218 |
+
line=dict(color="#8884d8", width=3),
|
219 |
+
hovertemplate="Month: %{x}<br>Volume: %{y}<extra></extra>"
|
220 |
+
)
|
221 |
+
)
|
222 |
|
223 |
+
fig.add_trace(
|
224 |
+
go.Scatter(
|
225 |
+
x=[item["month"] for item in data],
|
226 |
+
y=[item["competitionScore"] for item in data],
|
227 |
+
name="Competition Score",
|
228 |
+
line=dict(color="#82ca9d", width=3, dash="dot"),
|
229 |
+
hovertemplate="Month: %{x}<br>Score: %{y}<extra></extra>"
|
230 |
+
),
|
231 |
+
secondary_y=True
|
232 |
+
)
|
233 |
+
|
234 |
+
fig.add_trace(
|
235 |
+
go.Scatter(
|
236 |
+
x=[item["month"] for item in data],
|
237 |
+
y=[item["intentClarity"] for item in data],
|
238 |
+
name="Intent Clarity",
|
239 |
+
line=dict(color="#ffc658", width=3, dash="dash"),
|
240 |
+
hovertemplate="Month: %{x}<br>Clarity: %{y}<extra></extra>"
|
241 |
+
),
|
242 |
+
secondary_y=True
|
243 |
+
)
|
244 |
+
|
245 |
+
# Add trend line
|
246 |
+
x_values = list(range(len(data)))
|
247 |
+
y_values = [item["searchVolume"] for item in data]
|
248 |
+
|
249 |
+
# Simple linear regression
|
250 |
+
slope, intercept = np.polyfit(x_values, y_values, 1)
|
251 |
+
trend_y = [slope * x + intercept for x in x_values]
|
252 |
+
|
253 |
+
fig.add_trace(
|
254 |
+
go.Scatter(
|
255 |
+
x=[item["month"] for item in data],
|
256 |
+
y=trend_y,
|
257 |
+
name="Trend",
|
258 |
+
line=dict(color="rgba(255, 0, 0, 0.5)", width=2, dash="dot"),
|
259 |
+
hoverinfo="skip"
|
260 |
+
)
|
261 |
+
)
|
262 |
+
|
263 |
+
# Customize layout
|
264 |
+
fig.update_layout(
|
265 |
+
title=f"Keyword Evolution Forecast ({growth_scenario} Growth)",
|
266 |
+
title_font=dict(size=20),
|
267 |
+
hovermode="x unified",
|
268 |
+
xaxis=dict(
|
269 |
+
title="Month",
|
270 |
+
titlefont=dict(size=14),
|
271 |
+
showgrid=True,
|
272 |
+
gridcolor="rgba(0,0,0,0.1)"
|
273 |
+
),
|
274 |
+
yaxis=dict(
|
275 |
+
title="Search Volume",
|
276 |
+
titlefont=dict(size=14),
|
277 |
+
showgrid=True,
|
278 |
+
gridcolor="rgba(0,0,0,0.1)"
|
279 |
+
),
|
280 |
+
yaxis2=dict(
|
281 |
+
title="Score (0-100)",
|
282 |
+
titlefont=dict(size=14),
|
283 |
+
range=[0, 100]
|
284 |
+
),
|
285 |
+
legend=dict(
|
286 |
+
orientation="h",
|
287 |
+
yanchor="bottom",
|
288 |
+
y=1.02,
|
289 |
+
xanchor="center",
|
290 |
+
x=0.5
|
291 |
+
),
|
292 |
+
margin=dict(l=10, r=10, t=80, b=10),
|
293 |
+
height=500,
|
294 |
+
template="plotly_white"
|
295 |
+
)
|
296 |
+
|
297 |
+
# Add annotations for key insights
|
298 |
+
max_month_index = y_values.index(max(y_values))
|
299 |
+
fig.add_annotation(
|
300 |
+
x=data[max_month_index]["month"],
|
301 |
+
y=max(y_values),
|
302 |
+
text="Peak Volume",
|
303 |
+
showarrow=True,
|
304 |
+
arrowhead=1,
|
305 |
+
ax=0,
|
306 |
+
ay=-40
|
307 |
+
)
|
308 |
+
|
309 |
+
# Return the figure
|
310 |
+
return fig
|
311 |
+
|
312 |
except Exception as e:
|
313 |
print(f"Error in create_evolution_chart: {str(e)}")
|
314 |
+
# Create a simple error message plot with Plotly
|
315 |
+
import plotly.graph_objects as go
|
316 |
+
fig = go.Figure()
|
317 |
+
fig.add_annotation(
|
318 |
+
x=0.5, y=0.5,
|
319 |
+
text=f"Error creating chart: {str(e)}",
|
320 |
+
showarrow=False,
|
321 |
+
font=dict(size=14, color="red")
|
322 |
+
)
|
323 |
+
fig.update_layout(
|
324 |
+
xaxis=dict(showticklabels=False),
|
325 |
+
yaxis=dict(showticklabels=False)
|
326 |
+
)
|
327 |
+
return fig
|
328 |
|
329 |
+
def analyze_keyword(keyword, forecast_months=6, growth_scenario="Moderate", progress=gr.Progress()):
|
330 |
"""Main function to analyze a keyword"""
|
331 |
if not keyword or not keyword.strip():
|
332 |
return (
|
|
|
464 |
"Visual search integration"
|
465 |
]
|
466 |
|
467 |
+
# Generate more realistic and keyword-specific evolution data
|
468 |
+
base_volume = 1000 + (len(keyword) * 100)
|
469 |
+
|
470 |
+
# Adjust growth factor based on scenario
|
471 |
+
if growth_scenario == "Conservative":
|
472 |
+
growth_factor = 1.05 + (0.02 * (sum(ord(c) for c in keyword) % 5))
|
473 |
+
elif growth_scenario == "Aggressive":
|
474 |
+
growth_factor = 1.15 + (0.05 * (sum(ord(c) for c in keyword) % 5))
|
475 |
+
else: # Moderate
|
476 |
+
growth_factor = 1.1 + (0.03 * (sum(ord(c) for c in keyword) % 5))
|
477 |
+
|
478 |
+
evolution_data = []
|
479 |
+
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][:int(forecast_months)]
|
480 |
+
current_volume = base_volume
|
481 |
+
|
482 |
+
for month in months:
|
483 |
+
# Add some randomness to make it look more realistic
|
484 |
+
np.random.seed(sum(ord(c) for c in month + keyword))
|
485 |
+
random_factor = 0.9 + (0.2 * np.random.random())
|
486 |
+
current_volume *= growth_factor * random_factor
|
487 |
+
|
488 |
+
evolution_data.append({
|
489 |
+
"month": month,
|
490 |
+
"searchVolume": int(current_volume),
|
491 |
+
"competitionScore": min(95, 45 + (months.index(month) * 3) + (sum(ord(c) for c in keyword) % 10)),
|
492 |
+
"intentClarity": min(95, 80 + (months.index(month) * 2) + (sum(ord(c) for c in keyword) % 5))
|
493 |
+
})
|
494 |
|
495 |
progress(0.8, desc="Creating visualizations...")
|
496 |
+
# Create interactive evolution chart
|
497 |
+
evolution_chart = create_evolution_chart(evolution_data, forecast_months, growth_scenario)
|
498 |
|
499 |
# Generate HTML for token visualization
|
500 |
token_viz_html = generate_token_visualization_html(token_analysis, full_token_analysis)
|
|
|
514 |
"tokenAnalysis": full_token_analysis,
|
515 |
"intentAnalysis": intent_analysis,
|
516 |
"evolutionPotential": evolution_potential,
|
517 |
+
"predictedTrends": trends,
|
518 |
+
"forecast": {
|
519 |
+
"months": forecast_months,
|
520 |
+
"scenario": growth_scenario,
|
521 |
+
"data": evolution_data
|
522 |
+
}
|
523 |
}
|
524 |
|
525 |
progress(1.0, desc="Analysis complete!")
|
|
|
704 |
<div style="font-size: 12px; margin-bottom: 8px;">
|
705 |
<span style="font-weight: 500;">Origin: </span>
|
706 |
<span>{token['origin']['era']}, </span>
|
707 |
+
<span style="font-style: italic;">{token['origin']['language']}</span>
|
708 |
</div>
|
709 |
<div style="font-size: 12px; margin-bottom: 12px;">{token['origin']['note']}</div>
|
710 |
|
|
|
745 |
with gr.Column():
|
746 |
input_text = gr.Textbox(label="Enter keyword to analyze", placeholder="e.g. artificial intelligence")
|
747 |
|
748 |
+
# Add forecast settings
|
749 |
+
with gr.Accordion("Forecast Settings", open=False):
|
750 |
+
forecast_months = gr.Slider(minimum=3, maximum=12, value=6, step=1, label="Forecast Months")
|
751 |
+
growth_scenario = gr.Radio(["Conservative", "Moderate", "Aggressive"], value="Moderate", label="Growth Scenario")
|
752 |
+
|
753 |
# Add loading indicator
|
754 |
status_html = gr.HTML('<div style="color:gray;text-align:center;">Enter a keyword and click "Analyze DNA"</div>')
|
755 |
|
|
|
769 |
analysis_html = gr.HTML()
|
770 |
|
771 |
with gr.Tab("Evolution Chart"):
|
772 |
+
evolution_chart = gr.Plot(label="Keyword Evolution Forecast")
|
773 |
|
774 |
with gr.Tab("Raw Data"):
|
775 |
json_output = gr.JSON()
|
|
|
780 |
outputs=status_html
|
781 |
).then(
|
782 |
analyze_keyword,
|
783 |
+
inputs=[input_text, forecast_months, growth_scenario],
|
784 |
outputs=[token_viz_html, analysis_html, json_output, evolution_chart]
|
785 |
).then(
|
786 |
lambda: '<div style="color:green;text-align:center;">Analysis complete!</div>',
|
|
|
789 |
|
790 |
# Example buttons
|
791 |
for btn in example_btns:
|
792 |
+
# Define the function that will be called when an example button is clicked
|
793 |
+
def set_example(btn_label):
|
794 |
+
return btn_label
|
795 |
+
|
796 |
btn.click(
|
797 |
+
set_example,
|
798 |
inputs=[btn],
|
799 |
outputs=[input_text]
|
800 |
).then(
|
|
|
802 |
outputs=status_html
|
803 |
).then(
|
804 |
analyze_keyword,
|
805 |
+
inputs=[input_text, forecast_months, growth_scenario],
|
806 |
outputs=[token_viz_html, analysis_html, json_output, evolution_chart]
|
807 |
).then(
|
808 |
lambda: '<div style="color:green;text-align:center;">Analysis complete!</div>',
|