JARVIS / app.py
kingkolor8's picture
Update app.py
8a634ff verified
Raw
History Blame Contribute Delete
7.02 kB
import os
import time
import base64
import httpx
import asyncio
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel
from playwright.async_api import async_playwright
from contextlib import asynccontextmanager
# --- Configuration ---
IMGBB_API_KEY = os.getenv("IMGBB_API_KEY", "5765c99f7a977515ba320a689330e508")
SAVE_FOLDER = "/tmp/downloaded_images"
os.makedirs(SAVE_FOLDER, exist_ok=True)
class GeminiBot:
def __init__(self):
self.playwright = None
self.context = None
self.page = None
self.history = {"last_text": "", "last_img_id": ""}
async def start(self):
print("Starting Playwright...")
self.playwright = await async_playwright().start()
# HF Spaces కోసం Chromium + Headless వాడాలి
self.context = await self.playwright.chromium.launch_persistent_context(
user_data_dir="./user_data", # Local folder for session
channel='chromium', # msedge కాదు, chromium వాడాలి
headless=True, # True అయి ఉండాలి (Server కోసం)
accept_downloads=True,
args=[
"--disable-blink-features=AutomationControlled",
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage"
]
)
self.page = self.context.pages[0]
print("Navigating to Gemini...")
await self.page.goto("https://gemini.google.com")
try:
# లాగిన్ అయ్యాక మాత్రమే ఈ ఎలిమెంట్ కనిపిస్తుంది
await self.page.wait_for_selector("div[contenteditable='true']", timeout=60000)
print("--- Gemini Bot is ready (Logged In) ---")
except Exception as e:
print(f"Error: Login failed or selector not found. {e}")
await self.page.screenshot(path="debug_error.png")
# లాగిన్ ఫెయిల్ అయితే కూడా app run avvali kabatti raise cheyyakunda continue cheyyachu
# కానీ chat work avvakapovachu.
async def upload_to_imgbb(self, image_path):
if not IMGBB_API_KEY:
return None
try:
if not image_path or not os.path.exists(image_path):
return None
with open(image_path, "rb") as file:
img_base64 = base64.b64encode(file.read()).decode('utf-8')
async with httpx.AsyncClient() as client:
response = await client.post(
"https://api.imgbb.com/1/upload",
data={"key": IMGBB_API_KEY, "image": img_base64}
)
if response.status_code == 200:
return response.json()['data']['url']
else:
return None
except Exception as e:
print(f"--- [ERROR] Upload: {e} ---")
return None
async def download_image_expert(self):
try:
all_imgs = self.page.locator("img[src^='blob:']")
count = await all_imgs.count()
if count > 0:
target_img = all_imgs.last
img_src = await target_img.get_attribute("src")
if img_src == self.history["last_img_id"]:
return None
box = await target_img.bounding_box()
if box:
await self.page.mouse.move(box['x'] + (box['width'] / 2), box['y'] + (box['height'] / 2))
await asyncio.sleep(2)
download_btn = self.page.locator("button:has(mat-icon[fonticon='download'])").last
if await download_btn.is_visible():
async with self.page.expect_download(timeout=30000) as download_info:
try:
await download_btn.click(force=True)
except:
await self.page.evaluate("el => el.click()", await download_btn.element_handle())
downloaded_file = await download_info.value
file_name = f"gemini_{int(time.time())}.png"
save_path = os.path.join(SAVE_FOLDER, file_name)
await downloaded_file.save_as(save_path)
self.history["last_img_id"] = img_src
return save_path
except Exception as e:
print(f"--- [ERROR] Download: {e} ---")
return None
async def process_chat(self, message: str, file_paths: list = None):
try:
# File Upload Logic (Optional - needs adjustment for server paths)
if file_paths:
print("File upload requested but not fully implemented for server paths yet.")
# 1. Message Send
chat_box = self.page.locator("div[contenteditable='true']").first
await chat_box.fill(message)
await self.page.keyboard.press("Enter")
# 2. Wait for Response
stop_btn = self.page.locator("mat-icon[fonticon='stop']")
await self.page.wait_for_selector("message-content", timeout=60000)
while await stop_btn.is_visible():
await asyncio.sleep(0.5)
await asyncio.sleep(2)
# 3. Get Text
current_text = await self.page.evaluate("""
() => {
const msgs = document.querySelectorAll('message-content');
if (msgs.length > 0) return msgs[msgs.length - 1].innerText;
return '';
}
""")
# 4. Handle Image
img_path = await self.download_image_expert()
img_url = await self.upload_to_imgbb(img_path) if img_path else None
return {"text": current_text, "image_url": img_url}
except Exception as e:
return {"text": f"Error: {str(e)}", "image_url": None}
bot = GeminiBot()
@asynccontextmanager
async def lifespan(app: FastAPI):
await bot.start()
yield
if bot.context:
await bot.context.close()
if bot.playwright:
await bot.playwright.stop()
app = FastAPI(lifespan=lifespan)
class ChatRequest(BaseModel):
message: str
files: list = []
@app.get("/")
def health_check():
return {"status": "online", "message": "Gemini API is running"}
@app.post("/chat")
async def chat_api(request: ChatRequest):
result = await bot.process_chat(request.message, request.files)
return {"status": "success", "data": result}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)