Delta0723 commited on
Commit
da930c8
verified
1 Parent(s): 0b53ce7

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -370
app.py DELETED
@@ -1,370 +0,0 @@
1
- """
2
- TechMind PRO - Backend API
3
- FastAPI + Rate Limiting + Stripe
4
- """
5
-
6
- from fastapi import FastAPI, HTTPException, Depends, Header
7
- from fastapi.middleware.cors import CORSMiddleware
8
- from pydantic import BaseModel, EmailStr
9
- import sqlite3
10
- from datetime import datetime, timedelta
11
- from typing import Optional
12
- import os
13
- import hashlib
14
- import secrets
15
-
16
- # Importar funci贸n de inferencia
17
- from inference_techmind import generar_respuesta_api
18
-
19
- # =========================================================
20
- # CONFIGURACI脫N
21
- # =========================================================
22
- app = FastAPI(
23
- title="TechMind API",
24
- description="API para TechMind PRO",
25
- version="1.0.0"
26
- )
27
-
28
- # CORS (permite requests desde tu frontend)
29
- app.add_middleware(
30
- CORSMiddleware,
31
- allow_origins=[
32
- "https://techmind-landing.vercel.app",
33
- "http://localhost:3000",
34
- "http://localhost:8000"
35
- ],
36
- allow_credentials=True,
37
- allow_methods=["*"],
38
- allow_headers=["*"],
39
- )
40
-
41
- # L铆mites
42
- FREE_DAILY_LIMIT = 10
43
- PRO_DAILY_LIMIT = 999999
44
-
45
- # =========================================================
46
- # MODELOS PYDANTIC
47
- # =========================================================
48
- class QueryRequest(BaseModel):
49
- pregunta: str
50
- api_key: Optional[str] = None
51
-
52
- class QueryResponse(BaseModel):
53
- success: bool
54
- respuesta: Optional[str] = None
55
- tiempo_generacion: Optional[float] = None
56
- requests_restantes: Optional[int] = None
57
- error: Optional[str] = None
58
-
59
- class SignupRequest(BaseModel):
60
- email: EmailStr
61
-
62
- class APIKeyResponse(BaseModel):
63
- api_key: str
64
- plan: str
65
- expires_at: str
66
-
67
- # =========================================================
68
- # BASE DE DATOS
69
- # =========================================================
70
- def init_db():
71
- """Inicializa base de datos SQLite"""
72
- conn = sqlite3.connect('techmind.db')
73
- c = conn.cursor()
74
-
75
- # Tabla de API keys
76
- c.execute('''
77
- CREATE TABLE IF NOT EXISTS api_keys (
78
- api_key TEXT PRIMARY KEY,
79
- email TEXT NOT NULL,
80
- plan TEXT NOT NULL,
81
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
82
- expires_at TIMESTAMP,
83
- is_active BOOLEAN DEFAULT 1,
84
- stripe_customer_id TEXT,
85
- stripe_subscription_id TEXT
86
- )
87
- ''')
88
-
89
- # Tabla de requests diarios
90
- c.execute('''
91
- CREATE TABLE IF NOT EXISTS daily_requests (
92
- id INTEGER PRIMARY KEY AUTOINCREMENT,
93
- user_id TEXT NOT NULL,
94
- date TEXT NOT NULL,
95
- count INTEGER DEFAULT 0,
96
- UNIQUE(user_id, date)
97
- )
98
- ''')
99
-
100
- conn.commit()
101
- conn.close()
102
-
103
- init_db()
104
-
105
- def get_db():
106
- """Obtiene conexi贸n a DB"""
107
- conn = sqlite3.connect('techmind.db')
108
- conn.row_factory = sqlite3.Row
109
- return conn
110
-
111
- # =========================================================
112
- # RATE LIMITING
113
- # =========================================================
114
- def check_rate_limit(api_key: Optional[str] = None) -> tuple[bool, int, str]:
115
- """
116
- Verifica l铆mite de requests
117
-
118
- Returns:
119
- (puede_continuar, requests_restantes, user_id)
120
- """
121
-
122
- conn = get_db()
123
- c = conn.cursor()
124
-
125
- # Identificar usuario
126
- if api_key:
127
- # Usuario Pro
128
- c.execute("SELECT plan FROM api_keys WHERE api_key = ? AND is_active = 1", (api_key,))
129
- result = c.fetchone()
130
-
131
- if not result:
132
- conn.close()
133
- return False, 0, "invalid"
134
-
135
- user_id = api_key
136
- limit = PRO_DAILY_LIMIT
137
- else:
138
- # Usuario Free (identificar por IP o session)
139
- # En producci贸n usar铆as request.client.host
140
- user_id = "free_user"
141
- limit = FREE_DAILY_LIMIT
142
-
143
- # Contar requests hoy
144
- today = datetime.now().strftime("%Y-%m-%d")
145
-
146
- c.execute("""
147
- SELECT count FROM daily_requests
148
- WHERE user_id = ? AND date = ?
149
- """, (user_id, today))
150
-
151
- result = c.fetchone()
152
- count = result["count"] if result else 0
153
-
154
- if count >= limit:
155
- conn.close()
156
- return False, 0, user_id
157
-
158
- # Incrementar contador
159
- c.execute("""
160
- INSERT INTO daily_requests (user_id, date, count)
161
- VALUES (?, ?, 1)
162
- ON CONFLICT(user_id, date)
163
- DO UPDATE SET count = count + 1
164
- """, (user_id, today))
165
-
166
- conn.commit()
167
- conn.close()
168
-
169
- requests_restantes = limit - count - 1
170
-
171
- return True, requests_restantes, user_id
172
-
173
- # =========================================================
174
- # ENDPOINTS
175
- # =========================================================
176
-
177
- @app.get("/")
178
- async def root():
179
- """Health check"""
180
- return {
181
- "status": "ok",
182
- "service": "TechMind API",
183
- "version": "1.0.0"
184
- }
185
-
186
- @app.post("/api/query", response_model=QueryResponse)
187
- async def query_techmind(request: QueryRequest):
188
- """
189
- Endpoint principal para hacer preguntas a TechMind
190
- """
191
-
192
- # Validar pregunta
193
- if not request.pregunta or len(request.pregunta.strip()) < 3:
194
- raise HTTPException(400, "Pregunta demasiado corta")
195
-
196
- if len(request.pregunta) > 500:
197
- raise HTTPException(400, "Pregunta demasiado larga (m谩x 500 caracteres)")
198
-
199
- # Verificar rate limit
200
- puede_continuar, requests_restantes, user_id = check_rate_limit(request.api_key)
201
-
202
- if not puede_continuar:
203
- if user_id == "invalid":
204
- raise HTTPException(401, "API key inv谩lida")
205
- else:
206
- raise HTTPException(
207
- 429,
208
- f"L铆mite diario alcanzado. Upgrade a Pro para consultas ilimitadas."
209
- )
210
-
211
- # Generar respuesta
212
- try:
213
- resultado = generar_respuesta_api(request.pregunta)
214
-
215
- if not resultado["success"]:
216
- raise HTTPException(500, resultado.get("error", "Error generando respuesta"))
217
-
218
- return QueryResponse(
219
- success=True,
220
- respuesta=resultado["respuesta"],
221
- tiempo_generacion=resultado["tiempo_generacion"],
222
- requests_restantes=requests_restantes
223
- )
224
-
225
- except Exception as e:
226
- raise HTTPException(500, f"Error: {str(e)}")
227
-
228
- @app.post("/api/signup", response_model=APIKeyResponse)
229
- async def signup_free(request: SignupRequest):
230
- """
231
- Registro gratuito (genera API key)
232
- """
233
-
234
- conn = get_db()
235
- c = conn.cursor()
236
-
237
- # Verificar si email ya existe
238
- c.execute("SELECT api_key FROM api_keys WHERE email = ?", (request.email,))
239
- existing = c.fetchone()
240
-
241
- if existing:
242
- conn.close()
243
- raise HTTPException(400, "Email ya registrado")
244
-
245
- # Generar API key
246
- api_key = f"tm_free_{secrets.token_urlsafe(32)}"
247
-
248
- # Guardar en DB
249
- c.execute("""
250
- INSERT INTO api_keys (api_key, email, plan, is_active)
251
- VALUES (?, ?, 'free', 1)
252
- """, (api_key, request.email))
253
-
254
- conn.commit()
255
- conn.close()
256
-
257
- return APIKeyResponse(
258
- api_key=api_key,
259
- plan="free",
260
- expires_at="never"
261
- )
262
-
263
- @app.get("/api/stats")
264
- async def get_stats(api_key: str = Header(...)):
265
- """
266
- Obtiene estad铆sticas de uso
267
- """
268
-
269
- conn = get_db()
270
- c = conn.cursor()
271
-
272
- # Verificar API key
273
- c.execute("""
274
- SELECT email, plan, created_at
275
- FROM api_keys
276
- WHERE api_key = ? AND is_active = 1
277
- """, (api_key,))
278
-
279
- user = c.fetchone()
280
-
281
- if not user:
282
- conn.close()
283
- raise HTTPException(401, "API key inv谩lida")
284
-
285
- # Obtener requests hoy
286
- today = datetime.now().strftime("%Y-%m-%d")
287
-
288
- c.execute("""
289
- SELECT count FROM daily_requests
290
- WHERE user_id = ? AND date = ?
291
- """, (api_key, today))
292
-
293
- result = c.fetchone()
294
- requests_hoy = result["count"] if result else 0
295
-
296
- # Obtener total hist贸rico
297
- c.execute("""
298
- SELECT SUM(count) as total FROM daily_requests
299
- WHERE user_id = ?
300
- """, (api_key,))
301
-
302
- result = c.fetchone()
303
- requests_total = result["total"] if result and result["total"] else 0
304
-
305
- conn.close()
306
-
307
- limit = PRO_DAILY_LIMIT if user["plan"] == "pro" else FREE_DAILY_LIMIT
308
-
309
- return {
310
- "email": user["email"],
311
- "plan": user["plan"],
312
- "requests_hoy": requests_hoy,
313
- "requests_total": requests_total,
314
- "limite_diario": limit,
315
- "requests_restantes": limit - requests_hoy
316
- }
317
-
318
- # =========================================================
319
- # WEBHOOK STRIPE (para despu茅s)
320
- # =========================================================
321
- @app.post("/webhook/stripe")
322
- async def stripe_webhook():
323
- """
324
- Webhook para procesar pagos de Stripe
325
- TODO: Implementar cuando configures Stripe
326
- """
327
- return {"status": "pending_implementation"}
328
-
329
- # =========================================================
330
- # ADMIN (opcional - para ti)
331
- # =========================================================
332
- @app.get("/admin/users")
333
- async def list_users(admin_key: str = Header(...)):
334
- """
335
- Lista todos los usuarios (solo admin)
336
- """
337
-
338
- # Contrase帽a admin simple (cambiar en producci贸n)
339
- if admin_key != "admin_techmind_2025":
340
- raise HTTPException(403, "No autorizado")
341
-
342
- conn = get_db()
343
- c = conn.cursor()
344
-
345
- c.execute("""
346
- SELECT email, plan, created_at, is_active
347
- FROM api_keys
348
- ORDER BY created_at DESC
349
- LIMIT 100
350
- """)
351
-
352
- users = [dict(row) for row in c.fetchall()]
353
- conn.close()
354
-
355
- return {"users": users, "total": len(users)}
356
-
357
- # =========================================================
358
- # STARTUP
359
- # =========================================================
360
- @app.on_event("startup")
361
- async def startup_event():
362
- """Ejecutar al iniciar el servidor"""
363
- print("馃殌 TechMind API iniciada")
364
- print("馃搳 Base de datos: techmind.db")
365
- print("馃敀 CORS habilitado para: techmind-landing.vercel.app")
366
- print()
367
-
368
- if __name__ == "__main__":
369
- import uvicorn
370
- uvicorn.run(app, host="0.0.0.0", port=8000)