Bhatiasab commited on
Commit
14146a5
·
verified ·
1 Parent(s): cf5a806

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +164 -0
main.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import json
4
+ import asyncio
5
+ import uvicorn
6
+ import aiohttp
7
+ from fastapi import FastAPI, HTTPException
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from telethon import TelegramClient, events
10
+ from contextlib import asynccontextmanager
11
+
12
+ # --- CONFIG ---
13
+ API_ID = 21934109
14
+ API_HASH = 'e7e8c554b9ff88d180983996c33bdf27'
15
+ BOT_USERNAME = '@TruecallerInfoLookupBot'
16
+
17
+ PORT = int(os.environ.get("PORT", 7860))
18
+ SERVER_URL = f"http://127.0.0.1:{PORT}"
19
+
20
+ # Global coordination states
21
+ pending_phone_trigger = None
22
+ current_response_future = None
23
+
24
+ def parse_to_json(text: str) -> dict:
25
+ """Parses the bot text into a structured dictionary."""
26
+ e_match = re.search(r'Eyecon.*?Name:\s*`?(.*?)`?(?:\n|$)', text, re.IGNORECASE | re.DOTALL)
27
+ c_match = re.search(r'CALLAPP.*?Name:\s*`?(.*?)`?(?:\n|$)', text, re.IGNORECASE | re.DOTALL)
28
+
29
+ name1 = e_match.group(1).strip() if e_match else None
30
+ name2 = c_match.group(1).strip() if c_match else None
31
+
32
+ data = {}
33
+ if name1:
34
+ data["name1"] = name1
35
+ if name2:
36
+ data["name2"] = name2
37
+
38
+ if not name1 and not name2:
39
+ fallback = re.search(r'Name:\s*`?(.*?)`?(?:\n|$)', text, re.IGNORECASE)
40
+ if fallback:
41
+ data["name1"] = fallback.group(1).strip()
42
+
43
+ carrier_match = re.search(r'Carrier:\s*`?(.*?)`?(?:\n|$)', text, re.IGNORECASE)
44
+ location_match = re.search(r'Location:\s*`?(.*?)`?(?:\n|$)', text, re.IGNORECASE)
45
+
46
+ data["carrier"] = carrier_match.group(1).strip() if carrier_match else "N/A"
47
+ data["location"] = location_match.group(1).strip() if location_match else "N/A"
48
+ data["full_text"] = text
49
+
50
+ return data
51
+
52
+ # --- NATIVE FASTAPI ASYNC LIFECYCLE ---
53
+ @asynccontextmanager
54
+ async def lifespan(app: FastAPI):
55
+ session_path = "/code/lookup_session.session"
56
+ print(f"[STARTUP] Looking for session file at: {session_path}")
57
+
58
+ if not os.path.exists(session_path):
59
+ print(f"[CRITICAL ERROR] '{session_path}' IS MISSING!")
60
+ print("Please upload your authenticated 'lookup_session.session' file to your Space root.")
61
+ # We allow startup so you can see the log error instead of a crash-loop
62
+ else:
63
+ print("[STARTUP] Session file verified. Initializing Telegram Client...")
64
+ asyncio.create_task(run_telegram_worker())
65
+
66
+ yield
67
+ print("[SHUTDOWN] Cleaning up resources...")
68
+
69
+ app = FastAPI(lifespan=lifespan)
70
+
71
+ # --- CORS MIDDLEWARE ---
72
+ app.add_middleware(
73
+ CORSMiddleware,
74
+ allow_origins=["https://crm.gudmed.in"],
75
+ allow_credentials=True,
76
+ allow_methods=["*"],
77
+ allow_headers=["*"],
78
+ )
79
+
80
+ # --- INTERNAL INTER-TASK ROUTING ---
81
+ @app.get("/get-trigger")
82
+ async def get_trigger():
83
+ global pending_phone_trigger
84
+ if pending_phone_trigger:
85
+ phone = pending_phone_trigger
86
+ pending_phone_trigger = None
87
+ return {"phone": phone}
88
+ return {"phone": None}
89
+
90
+ @app.post("/webhook-receive")
91
+ async def webhook_receive(payload: dict):
92
+ global current_response_future
93
+ if current_response_future and not current_response_future.done():
94
+ current_response_future.set_result(payload)
95
+ return {"status": "ok"}
96
+
97
+ # --- PUBLIC ENDPOINT ---
98
+ @app.get("/lookup")
99
+ async def lookup(phone: str):
100
+ global current_response_future, pending_phone_trigger
101
+ clean_phone = str(phone)[-10:].strip()
102
+
103
+ loop = asyncio.get_running_loop()
104
+ current_response_future = loop.create_future()
105
+ pending_phone_trigger = clean_phone
106
+
107
+ try:
108
+ # Await responses asynchronously without manual interval polling
109
+ result_data = await asyncio.wait_for(current_response_future, timeout=20.0)
110
+ return {
111
+ "status": "success",
112
+ "phone": clean_phone,
113
+ "data": result_data
114
+ }
115
+ except asyncio.TimeoutError:
116
+ raise HTTPException(status_code=504, detail="Timeout: Bot did not respond in time.")
117
+ finally:
118
+ current_response_future = None
119
+
120
+ # --- TELETHON WORKER ---
121
+ async def poll_server_for_outbound(client):
122
+ while True:
123
+ try:
124
+ async with aiohttp.ClientSession() as session:
125
+ async with session.get(f"{SERVER_URL}/get-trigger") as resp:
126
+ if resp.status == 200:
127
+ data = await resp.json()
128
+ phone = data.get("phone")
129
+ if phone:
130
+ print(f"[WORKER] Sending target: +91{phone}")
131
+ await client.send_message(BOT_USERNAME, f'+91{phone}')
132
+ except Exception as e:
133
+ print(f"[WORKER ERROR] Outbound connection glitch: {e}")
134
+ await asyncio.sleep(0.1)
135
+
136
+ async def run_telegram_worker():
137
+ client = TelegramClient('/code/lookup_session', API_ID, API_HASH)
138
+
139
+ @client.on(events.NewMessage(chats=BOT_USERNAME))
140
+ async def handle_bot_reply(event):
141
+ text = event.text or ""
142
+ # Filter out status indicators
143
+ if any(x in text for x in ["Searching", "Please wait", "Typing"]):
144
+ return
145
+
146
+ print("[INBOUND] Message received from bot. Parsing...")
147
+ parsed_data = parse_to_json(text)
148
+
149
+ try:
150
+ async with aiohttp.ClientSession() as session:
151
+ await session.post(f"{SERVER_URL}/webhook-receive", json=parsed_data)
152
+ except Exception as e:
153
+ print(f"[INBOUND ERROR] Could not forward data: {e}")
154
+
155
+ await client.start()
156
+ print("[BACKGROUND] Telegram Client Authorized and Active!")
157
+
158
+ await asyncio.gather(
159
+ client.run_until_disconnected(),
160
+ poll_server_for_outbound(client)
161
+ )
162
+
163
+ if __name__ == "__main__":
164
+ uvicorn.run(app, host="0.0.0.0", port=PORT)