Spaces:
Runtime error
Runtime error
| # interface.py | |
| import os | |
| # Set CrewAI storage directory to something writable BEFORE any imports | |
| os.environ["CREWAI_STORAGE_DIR"] = "/tmp/crewai" | |
| os.environ["CREWAI_TELEMETRY_ENABLED"] = "false" | |
| os.environ["CREWAI_DB_PATH"] = "/tmp/crewai/crewai.db" | |
| os.environ["CREWAI_MEMORY_ENABLED"] = "false" | |
| os.environ["CREWAI_TRACING_ENABLED"] = "false" | |
| os.environ["CREWAI_AUTH_ENABLED"] = "false" | |
| os.environ["CREWAI_CREDENTIALS_PATH"] = "/tmp/crewai/credentials" | |
| os.environ["CREWAI_SECURE_STORAGE_PATH"] = "/tmp/crewai/secure" | |
| # Create the directories if they don't exist | |
| os.makedirs("/tmp/crewai", exist_ok=True) | |
| os.makedirs("/tmp/crewai/credentials", exist_ok=True) | |
| os.makedirs("/tmp/crewai/secure", exist_ok=True) | |
| import gradio as gr | |
| from crewai import Crew, Process | |
| from agents import finance_knowledge_agent, market_news_agent, stock_analysis_agent, response_refiner_agent | |
| from tasks import get_finance_knowledge_task, get_market_news_task, get_stock_analysis_task, get_response_refiner_task | |
| from utils import determine_question_type, search_qdrant | |
| # Initialize Crew | |
| finance_crew = Crew( | |
| agents=[finance_knowledge_agent, market_news_agent, stock_analysis_agent, response_refiner_agent], | |
| tasks=[], | |
| process=Process.sequential, | |
| verbose=1 | |
| ) | |
| def get_response(query): | |
| """Get chatbot response.""" | |
| finance_crew.tasks = [] # Reset tasks for each query | |
| try: | |
| question_type, processed_query = determine_question_type(query) | |
| # Determine RAG usage | |
| rag_note = "RAG_SUFFICIENT" # Default for finance_knowledge | |
| if question_type == "finance_knowledge": | |
| contexts = search_qdrant(query, top_k=2) | |
| if contexts and len(contexts) > 0: | |
| shortened_contexts = [] | |
| for ctx in contexts: | |
| text = ctx["text"] | |
| if len(text) > 300: | |
| text = text[:297] + "..." | |
| shortened_contexts.append({ | |
| "source": ctx["source"], | |
| "text": text | |
| }) | |
| context_text = "\n\n".join([f"Source: {ctx['source']}\nContent: {ctx['text']}" for ctx in shortened_contexts]) | |
| is_context_useful = len(context_text) > 30 and any(keyword in context_text.lower() for keyword in query.lower().split()) | |
| rag_note = "RAG_SUFFICIENT" if is_context_useful else "RAG_NOT_USED" | |
| else: | |
| rag_note = "RAG_NOT_USED" | |
| initial_task = get_finance_knowledge_task(query) | |
| elif question_type == "market_news": | |
| rag_note = "NO_RAG_NEEDED" | |
| initial_task = get_market_news_task(query) | |
| elif question_type == "stock_analysis": | |
| rag_note = "NO_RAG_NEEDED" | |
| initial_task = get_stock_analysis_task(processed_query) | |
| else: | |
| initial_task = get_finance_knowledge_task(query) | |
| finance_crew.tasks.append(initial_task) | |
| initial_response = finance_crew.kickoff() | |
| refiner_task = get_response_refiner_task(query, initial_response, question_type, rag_note=rag_note) | |
| finance_crew.tasks = [refiner_task] | |
| final_report = finance_crew.kickoff() | |
| return final_report | |
| except Exception as e: | |
| return f"Error: {e}\nPlease try again." | |
| # CSS | |
| custom_css = """ | |
| :root { | |
| --primary-color: #00416a; | |
| --secondary-color: #047fb7; | |
| --title-color: #FFD700; | |
| --text-color: #ffffff; | |
| --bg-dark: #1a1a1a; | |
| --bg-medium: #2a2a2a; | |
| --bg-light: #353535; | |
| --input-bg: #ffffff; | |
| --input-text: #333333; | |
| --button-green: #4CAF50; | |
| } | |
| body, html { | |
| background-color: #1a1a1a !important; | |
| margin: 0; | |
| padding: 0; | |
| width: 100%; | |
| height: 100%; | |
| overflow-x: hidden; | |
| } | |
| .gradio-container { | |
| background: linear-gradient(135deg, #1a1a1a 0%, #00416a 100%) !important; | |
| font-family: 'Montserrat', 'Arial', sans-serif !important; | |
| max-width: 100% !important; | |
| width: 100% !important; | |
| margin: 0 !important; | |
| padding: 25px !important; | |
| min-height: 100vh !important; | |
| } | |
| .gradio-container .input-box, | |
| .gradio-container .output-box, | |
| .gr-form, | |
| .gr-box, | |
| .gr-padded, | |
| .gr-panel, | |
| .gr-input, | |
| .gr-input-label, | |
| textarea, | |
| .gr-textarea, | |
| .gr-textbox { | |
| background-color: #ffffff !important; | |
| } | |
| textarea, | |
| .gr-textarea textarea, | |
| .gr-textbox textarea, | |
| .gr-textbox input { | |
| background-color: #ffffff !important; | |
| color: #333333 !important; | |
| } | |
| .gr-button.submit-button { | |
| background-color: #4CAF50 !important; | |
| color: #ffffff !important; | |
| border: none !important; | |
| padding: 10px 20px !important; | |
| border-radius: 8px !important; | |
| font-weight: bold !important; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2) !important; | |
| text-align: center !important; | |
| width: 150px !important; | |
| margin: 10px auto !important; | |
| display: block !important; | |
| } | |
| button, | |
| .gr-button span, | |
| .submit-button span { | |
| color: #ffffff !important; | |
| background-color: transparent !important; | |
| } | |
| .examples-title, | |
| .gr-examples .gr-interface-title, | |
| footer div, | |
| footer span { | |
| color: #ffffff !important; | |
| background-color: transparent !important; | |
| font-weight: bold !important; | |
| } | |
| .gr-box { | |
| border-radius: 8px !important; | |
| padding: 12px !important; | |
| background-color: #ffffff !important; | |
| border: 1px solid #047fb7 !important; | |
| } | |
| label, .gr-block.gr-box label { | |
| color: #ffffff !important; | |
| font-weight: bold !important; | |
| background-color: transparent !important; | |
| } | |
| .gr-examples .gr-sample-btn { | |
| background-color: #e0e0e0 !important; | |
| border: 1px solid #047fb7 !important; | |
| color: #333333 !important; | |
| border-radius: 8px !important; | |
| } | |
| h1 { | |
| color: #FFD700 !important; | |
| text-align: center !important; | |
| text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3) !important; | |
| font-weight: bold !important; | |
| } | |
| h3 { | |
| color: #ffffff !important; | |
| text-align: center !important; | |
| } | |
| .finance-icons { | |
| text-align: center !important; | |
| color: #ffffff !important; | |
| } | |
| .ticker-tape { | |
| background-color: #353535 !important; | |
| overflow: hidden !important; | |
| white-space: nowrap !important; | |
| padding: 8px 0 !important; | |
| margin: 15px 0 !important; | |
| border-radius: 5px !important; | |
| } | |
| .ticker-content { | |
| display: inline-block !important; | |
| animation: ticker 30s linear infinite !important; | |
| color: #ffffff !important; | |
| } | |
| @keyframes ticker { | |
| 0% { transform: translateX(100%); } | |
| 100% { transform: translateX(-100%); } | |
| } | |
| .stock-symbol { | |
| margin: 0 15px !important; | |
| display: inline-block !important; | |
| color: #ffffff !important; | |
| font-weight: bold !important; | |
| } | |
| .up { color: #4CAF50 !important; } | |
| .down { color: #FF5252 !important; } | |
| .examples { | |
| background-color: #ffffff !important; | |
| border-radius: 8px !important; | |
| padding: 10px !important; | |
| } | |
| .footer-container, .footer, .gr-footnote { | |
| display: none !important; | |
| } | |
| .gradio-container .prose, | |
| .gradio-container .prose p { | |
| background-color: transparent !important; | |
| } | |
| """ | |
| # HTML components for design | |
| ticker_html = """ | |
| <div class="ticker-tape"> | |
| <div class="ticker-content"> | |
| <span class="stock-symbol">AAPL <span class="up">+1.2%</span></span> | |
| <span class="stock-symbol">MSFT <span class="up">+0.8%</span></span> | |
| <span class="stock-symbol">GOOGL <span class="down">-0.4%</span></span> | |
| <span class="stock-symbol">AMZN <span class="up">+2.1%</span></span> | |
| <span class="stock-symbol">TSLA <span class="down">-1.7%</span></span> | |
| <span class="stock-symbol">JPM <span class="up">+0.5%</span></span> | |
| <span class="stock-symbol">BAC <span class="down">-0.2%</span></span> | |
| <span class="stock-symbol">WMT <span class="up">+0.3%</span></span> | |
| </div> | |
| </div> | |
| """ | |
| finance_icons = """ | |
| <div class="finance-icons"> | |
| <span style="color: #4CAF50;">π π πΉ π° π π¦ π </span> | |
| </div> | |
| """ | |
| # Gradio interface | |
| with gr.Blocks(css=custom_css, theme=gr.themes.Base(), analytics_enabled=False) as interface: | |
| gr.HTML("<h1>Professional Finance Assistant</h1>") | |
| gr.HTML("<h3>Your AI-powered financial advisor and market analyst</h3>") | |
| gr.HTML(finance_icons) | |
| gr.HTML(ticker_html) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| input_text = gr.Textbox( | |
| lines=4, | |
| placeholder="Ask me anything about finance (e.g., 'What is dividend investing?', 'Analyze Tesla stock', 'Latest market news on tech sector')", | |
| label="Your Financial Query", | |
| show_label=True, | |
| interactive=True | |
| ) | |
| submit_btn = gr.Button("Submit", elem_classes=["submit-button"]) | |
| output_text = gr.Textbox(label="Financial Analysis", lines=10) | |
| example_queries = [ | |
| ["What is the difference between bull and bear markets?"], | |
| ["Analyze AAPL stock performance"], | |
| ["Latest news about cryptocurrency market"], | |
| ["Explain P/E ratio and its importance"] | |
| ] | |
| gr.Examples(example_queries, inputs=input_text, examples_per_page=5, label="Examples") | |
| # Event handlers | |
| submit_btn.click(fn=get_response, inputs=input_text, outputs=output_text) | |
| # Launch the interface | |
| interface.launch(share=False, inbrowser=True) |