Fefev / app.py
Mayank2027's picture
Create app.py
0411bd3 verified
Raw
History Blame Contribute Delete
17.7 kB
import os
output_dir = "/mnt/agents/output"
# 5. app.py - Updated for local model with loading indicator
app_content = r'''import os
import sys
import gradio as gr
import tempfile
import uuid
from pathlib import Path
from config import ALLOWED_EXTENSIONS, MAX_FILE_SIZE, JAILBREAK_SYSTEM_PROMPT
from agent import AgentManager, AutonomousAgent, ModelLoader
from tools import describe_image, ocr_image, read_file
# Initialize agent manager
agent_manager = AgentManager()
# CSS for premium dark theme
CUSTOM_CSS = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
:root {
--bg-primary: #0d1117;
--bg-secondary: #161b22;
--bg-tertiary: #21262d;
--bg-hover: #30363d;
--border-color: #30363d;
--text-primary: #e6edf3;
--text-secondary: #8b949e;
--text-muted: #6e7681;
--accent-primary: #58a6ff;
--accent-secondary: #1f6feb;
--accent-success: #3fb950;
--accent-warning: #d29922;
--accent-danger: #f85149;
--accent-purple: #bc8cff;
--accent-cyan: #39c5cf;
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', monospace;
}
* {
font-family: var(--font-sans) !important;
}
body, .gradio-container {
background-color: var(--bg-primary) !important;
color: var(--text-primary) !important;
}
.gradio-container {
max-width: 1200px !important;
padding: 0 !important;
}
.header-container {
background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-primary) 100%);
border-bottom: 1px solid var(--border-color);
padding: 24px 32px;
margin-bottom: 0;
}
.header-title {
font-size: 28px;
font-weight: 700;
color: var(--text-primary);
margin: 0;
letter-spacing: -0.5px;
}
.header-subtitle {
font-size: 14px;
color: var(--text-secondary);
margin-top: 4px;
}
.header-badge {
display: inline-block;
background: linear-gradient(135deg, var(--accent-secondary), var(--accent-purple));
color: white;
padding: 2px 10px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
margin-left: 10px;
vertical-align: middle;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.chatbot-container {
background: var(--bg-primary) !important;
border: 1px solid var(--border-color) !important;
border-radius: 12px !important;
min-height: 500px;
}
.chatbot-container .message {
border-radius: 12px !important;
padding: 14px 18px !important;
margin: 8px 0 !important;
font-size: 14px !important;
line-height: 1.6 !important;
}
.chatbot-container .message.user {
background: linear-gradient(135deg, var(--accent-secondary), #2d7d9a) !important;
color: white !important;
margin-left: 40px !important;
border-bottom-right-radius: 4px !important;
}
.chatbot-container .message.bot {
background: var(--bg-secondary) !important;
color: var(--text-primary) !important;
margin-right: 40px !important;
border: 1px solid var(--border-color) !important;
border-bottom-left-radius: 4px !important;
}
.chatbot-container .message.bot pre {
background: var(--bg-primary) !important;
border: 1px solid var(--border-color) !important;
border-radius: 8px !important;
padding: 12px !important;
overflow-x: auto !important;
}
.chatbot-container .message.bot code {
font-family: var(--font-mono) !important;
font-size: 13px !important;
color: var(--accent-cyan) !important;
}
.chatbot-container .message.bot pre code {
color: var(--text-primary) !important;
}
.input-container {
background: var(--bg-secondary) !important;
border: 1px solid var(--border-color) !important;
border-radius: 12px !important;
padding: 16px !important;
}
.input-container textarea {
background: var(--bg-primary) !important;
border: 1px solid var(--border-color) !important;
border-radius: 8px !important;
color: var(--text-primary) !important;
font-size: 14px !important;
padding: 12px !important;
resize: none !important;
}
.input-container textarea:focus {
border-color: var(--accent-primary) !important;
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1) !important;
outline: none !important;
}
.input-container textarea::placeholder {
color: var(--text-muted) !important;
}
button.primary {
background: linear-gradient(135deg, var(--accent-secondary), var(--accent-primary)) !important;
color: white !important;
border: none !important;
border-radius: 8px !important;
padding: 10px 20px !important;
font-weight: 600 !important;
font-size: 14px !important;
transition: all 0.2s ease !important;
}
button.primary:hover {
transform: translateY(-1px) !important;
box-shadow: 0 4px 12px rgba(31, 111, 235, 0.3) !important;
}
button.secondary {
background: var(--bg-tertiary) !important;
color: var(--text-primary) !important;
border: 1px solid var(--border-color) !important;
border-radius: 8px !important;
padding: 10px 20px !important;
font-weight: 500 !important;
font-size: 14px !important;
transition: all 0.2s ease !important;
}
button.secondary:hover {
background: var(--bg-hover) !important;
border-color: var(--text-muted) !important;
}
button.danger {
background: var(--accent-danger) !important;
color: white !important;
border: none !important;
border-radius: 8px !important;
padding: 10px 20px !important;
font-weight: 600 !important;
font-size: 14px !important;
}
.controls-panel {
background: var(--bg-secondary) !important;
border: 1px solid var(--border-color) !important;
border-radius: 12px !important;
padding: 20px !important;
}
.controls-panel h3 {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 16px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.upload-container {
background: var(--bg-primary) !important;
border: 2px dashed var(--border-color) !important;
border-radius: 12px !important;
padding: 20px !important;
text-align: center !important;
transition: all 0.2s ease !important;
}
.upload-container:hover {
border-color: var(--accent-primary) !important;
background: rgba(88, 166, 255, 0.05) !important;
}
.status-indicator {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
font-weight: 500;
padding: 4px 10px;
border-radius: 20px;
background: var(--bg-tertiary);
}
.status-indicator.online {
color: var(--accent-success);
}
.status-indicator.online::before {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--accent-success);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-primary);
}
::-webkit-scrollbar-thumb {
background: var(--bg-hover);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
.tool-badge {
display: inline-block;
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
color: var(--accent-primary);
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
font-family: var(--font-mono);
font-weight: 500;
}
.loading-dots {
display: inline-flex;
gap: 4px;
}
.loading-dots span {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--accent-primary);
animation: bounce 1.4s infinite ease-in-out both;
}
.loading-dots span:nth-child(1) { animation-delay: -0.32s; }
.loading-dots span:nth-child(2) { animation-delay: -0.16s; }
@keyframes bounce {
0%, 80%, 100% { transform: scale(0); }
40% { transform: scale(1); }
}
@media (max-width: 768px) {
.header-container {
padding: 16px 20px;
}
.header-title {
font-size: 22px;
}
.chatbot-container {
min-height: 350px;
}
}
.gr-box, .gr-form, .gr-panel {
background: var(--bg-secondary) !important;
border-color: var(--border-color) !important;
}
.gr-input, .gr-textarea {
background: var(--bg-primary) !important;
border-color: var(--border-color) !important;
color: var(--text-primary) !important;
}
.gr-button {
border-radius: 8px !important;
}
.gr-slider {
accent-color: var(--accent-primary) !important;
}
.gr-checkbox {
accent-color: var(--accent-primary) !important;
}
.gr-image {
border-radius: 12px !important;
border: 1px solid var(--border-color) !important;
}
.copy-btn {
position: absolute;
top: 8px;
right: 8px;
background: var(--bg-hover) !important;
border: 1px solid var(--border-color) !important;
color: var(--text-secondary) !important;
padding: 4px 10px !important;
border-radius: 6px !important;
font-size: 11px !important;
cursor: pointer !important;
opacity: 0;
transition: opacity 0.2s ease;
}
pre:hover .copy-btn {
opacity: 1;
}
.copy-btn:hover {
background: var(--bg-tertiary) !important;
color: var(--text-primary) !important;
}
"""
# Session storage
user_sessions = {}
def get_session_id():
"""Generate a unique session ID."""
return str(uuid.uuid4())
def process_file_upload(file_obj):
"""Process uploaded file and return content/description."""
if file_obj is None:
return None, "No file uploaded."
file_path = file_obj.name if hasattr(file_obj, 'name') else str(file_obj)
ext = Path(file_path).suffix.lower()
if ext not in ALLOWED_EXTENSIONS:
return None, f"Unsupported file type: {ext}. Allowed: {', '.join(ALLOWED_EXTENSIONS)}"
# Check file size
try:
size = os.path.getsize(file_path)
if size > MAX_FILE_SIZE:
return None, f"File too large: {size / 1024 / 1024:.1f}MB (max {MAX_FILE_SIZE / 1024 / 1024}MB)"
except:
pass
# Read file content
content = read_file(file_path)
# For images, also describe them
if ext in ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']:
description = describe_image(file_path)
return content, f"**Image uploaded.**\n\n**AI Description:** {description}\n\n**OCR Text:** {ocr_image(file_path)}"
return content, f"**File uploaded:** `{Path(file_path).name}`\n\n**Content preview:**\n```\n{content[:2000]}{'...' if len(content) > 2000 else ''}\n```"
def chat_response(message, history, session_id, deepthink, force_search, image_file, doc_file):
"""Process chat message and return streaming response."""
if not session_id:
session_id = get_session_id()
agent = agent_manager.get_agent(session_id)
# Process file uploads
file_context = ""
if image_file is not None:
_, file_info = process_file_upload(image_file)
file_context += f"\n\n{file_info}"
if doc_file is not None:
content, file_info = process_file_upload(doc_file)
file_context += f"\n\n{file_info}"
# Combine message with file context
full_message = message + file_context if file_context else message
# Stream the response
bot_response = ""
for text, is_final in agent.run_stream(full_message, deepthink=deepthink, force_search=force_search):
bot_response += text
if is_final:
break
# Yield intermediate updates for streaming effect
yield bot_response, history + [[message, bot_response]], session_id
# Final yield
history.append([message, bot_response])
yield "", history, session_id
def new_chat():
"""Start a new chat session."""
session_id = get_session_id()
return [], session_id, ""
def create_interface():
"""Create the Gradio interface."""
with gr.Blocks(css=CUSTOM_CSS, title="AI Agent - Local") as demo:
# Session state
session_id = gr.State(value=get_session_id())
# Header
with gr.Row():
with gr.Column():
gr.HTML("""
<div class="header-container">
<h1 class="header-title">
AI Agent
<span class="header-badge">Local 8B</span>
</h1>
<p class="header-subtitle">Llama 3.1 8B Instruct Q4_K_M | 60+ Tools | Fully Offline | No API Key</p>
</div>
""")
# Main layout
with gr.Row():
# Left sidebar - Controls
with gr.Column(scale=1, min_width=250):
with gr.Column(elem_classes=["controls-panel"]):
gr.Markdown("### Controls")
deepthink_toggle = gr.Checkbox(
label="DeepThink",
value=False,
info="Enable step-by-step reasoning"
)
force_search_toggle = gr.Checkbox(
label="Force Search",
value=False,
info="Always search the web first"
)
gr.Markdown("---")
new_chat_btn = gr.Button(
"New Chat",
variant="secondary",
size="sm"
)
gr.Markdown("---")
gr.Markdown("### Upload Files")
image_upload = gr.Image(
label="Image",
type="filepath",
height=150,
elem_classes=["upload-container"]
)
file_upload = gr.File(
label="Document",
file_types=[".pdf", ".docx", ".txt", ".py", ".json", ".csv", ".html", ".md", ".xml", ".yaml", ".yml", ".js", ".css", ".sql"],
height=100,
elem_classes=["upload-container"]
)
gr.Markdown("---")
gr.Markdown("""
<div style="font-size: 11px; color: var(--text-muted);">
<b>Available Tools:</b><br/>
Web Search, Browse, Screenshot, PDF, OCR, Translate, Weather, News, Stocks, Calculator, Python, Shell, File Ops, Base64, Hash, Password, QR, Barcode, URL Shortener, DNS, IP Lookup, WHOIS, Ping, Port Scan, Encode/Decode, HTML/Markdown, JSON/CSV, Random, UUID, Timestamp, Word Count, Diff, Regex, Sentiment, Summarize, NER, YouTube, Links, Emails, Phones, Currency, Units, Code Format, Git, System Info, Directory, Compress
</div>
""")
# Right side - Chat
with gr.Column(scale=3):
# Chatbot
chatbot = gr.Chatbot(
label="",
height=550,
elem_classes=["chatbot-container"],
bubble_full_width=False,
show_copy_button=True,
latex_delimiters=[{"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False}],
render_markdown=True
)
# Input area
with gr.Row():
msg_input = gr.Textbox(
placeholder="Ask anything... The AI can search the web, run code, analyze files, and more.",
show_label=False,
lines=2,
max_lines=5,
container=False,
elem_classes=["input-container"]
)
with gr.Row():
submit_btn = gr.Button("Send", variant="primary", size="sm")
clear_btn = gr.Button("Clear", variant="secondary", size="sm")
# Event handlers
submit_btn.click(
fn=chat_response,
inputs=[msg_input, chatbot, session_id, deepthink_toggle, force_search_toggle, image_upload, file_upload],
outputs=[msg_input, chatbot, session_id]
)
msg_input.submit(
fn=chat_response,
inputs=[msg_input, chatbot, session_id, deepthink_toggle, force_search_toggle, image_upload, file_upload],
outputs=[msg_input, chatbot, session_id]
)
new_chat_btn.click(
fn=new_chat,
outputs=[chatbot, session_id, msg_input]
)
clear_btn.click(
fn=lambda: ([], get_session_id(), ""),
outputs=[chatbot, session_id, msg_input]
)
return demo
if __name__ == "__main__":
demo = create_interface()
demo.launch(
server_name="0.0.0.0",
server_port=int(os.getenv("PORT", 7860)),
share=False,
show_api=False,
favicon_path=None
)
'''
with open(f"{output_dir}/app.py", "w") as f:
f.write(app_content)
print("app.py written")
import py_compile
try:
py_compile.compile(f"{output_dir}/app.py", doraise=True)
print("app.py compiles successfully!")
except Exception as e:
print(f"Compile error: {e}")