Akoda35 commited on
Commit
a63bbe1
·
verified ·
1 Parent(s): c917370

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +214 -7
app.py CHANGED
@@ -1,19 +1,226 @@
1
- from fastapi import FastAPI
2
- from fastapi.responses import HTMLResponse
 
 
 
3
  from fastapi.staticfiles import StaticFiles
4
  from fastapi.templating import Jinja2Templates
5
- from fastapi import Request
6
- import os
7
 
8
- app = FastAPI(title="PyRunner AI Space")
 
 
 
 
9
 
10
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
11
 
12
  templates = Jinja2Templates(directory=os.path.join(BASE_DIR, "templates"))
13
 
14
- app.mount("/static", StaticFiles(directory=os.path.join(BASE_DIR, "static")), name="static")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  @app.get("/", response_class=HTMLResponse)
18
  async def home(request: Request):
19
- return templates.TemplateResponse("index.html", {"request": request})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import requests
4
+ from fastapi import FastAPI, Request, Header
5
+ from fastapi.responses import HTMLResponse, JSONResponse
6
  from fastapi.staticfiles import StaticFiles
7
  from fastapi.templating import Jinja2Templates
 
 
8
 
9
+ # =========================
10
+ # APP INIT
11
+ # =========================
12
+
13
+ app = FastAPI(title="PyRunner AI Space", version="1.0")
14
 
15
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
16
 
17
  templates = Jinja2Templates(directory=os.path.join(BASE_DIR, "templates"))
18
 
19
+ static_path = os.path.join(BASE_DIR, "static")
20
+ if os.path.exists(static_path):
21
+ app.mount("/static", StaticFiles(directory=static_path), name="static")
22
+
23
+
24
+ # =========================
25
+ # ENV
26
+ # =========================
27
+
28
+ OLLAMA_URL = os.getenv("OLLAMA_URL", "http://localhost:11434")
29
+ OLLAMA_FALLBACK_URL = os.getenv("OLLAMA_FALLBACK_URL")
30
+
31
+ OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "qwen2.5:1.5b")
32
+ OLLAMA_CODE_MODEL = os.getenv("OLLAMA_CODE_MODEL", "qwen2.5-coder:1.5b")
33
+ OLLAMA_FAST_MODEL = os.getenv("OLLAMA_FAST_MODEL", "deepseek-coder:1.3b")
34
+ OLLAMA_BACKUP_MODEL = os.getenv("OLLAMA_BACKUP_MODEL", "llama3.2:1b")
35
+
36
+ OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
37
+ OPENROUTER_MODEL = os.getenv("OPENROUTER_MODEL")
38
+
39
+ SUPABASE_URL = os.getenv("SUPABASE_URL")
40
+ SUPABASE_KEY = os.getenv("SUPABASE_KEY")
41
+
42
+
43
+ # =========================
44
+ # SAFE OLLAMA CALL
45
+ # =========================
46
+
47
+ def call_ollama(prompt: str, model: str):
48
+ try:
49
+ r = requests.post(
50
+ f"{OLLAMA_URL}/api/generate",
51
+ json={
52
+ "model": model,
53
+ "prompt": prompt,
54
+ "stream": False
55
+ },
56
+ timeout=60
57
+ )
58
+ return r.json()
59
+ except Exception as e:
60
+ return {"error": str(e)}
61
+
62
 
63
+ # =========================
64
+ # OPENROUTER FALLBACK
65
+ # =========================
66
+
67
+ def call_openrouter(prompt: str):
68
+ if not OPENROUTER_API_KEY:
69
+ return {"error": "No OpenRouter key"}
70
+
71
+ try:
72
+ r = requests.post(
73
+ "https://openrouter.ai/api/v1/chat/completions",
74
+ headers={
75
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
76
+ "Content-Type": "application/json"
77
+ },
78
+ json={
79
+ "model": OPENROUTER_MODEL,
80
+ "messages": [
81
+ {"role": "user", "content": prompt}
82
+ ]
83
+ },
84
+ timeout=60
85
+ )
86
+ return r.json()
87
+ except Exception as e:
88
+ return {"error": str(e)}
89
+
90
+
91
+ # =========================
92
+ # ROUTER (1B–2B ONLY LOGIC)
93
+ # =========================
94
+
95
+ def route_model(task: str):
96
+ task = task.lower()
97
+
98
+ if "code" in task or "script" in task:
99
+ return OLLAMA_CODE_MODEL
100
+
101
+ if "fast" in task:
102
+ return OLLAMA_FAST_MODEL
103
+
104
+ if "fallback" in task:
105
+ return OLLAMA_BACKUP_MODEL
106
+
107
+ return OLLAMA_MODEL
108
+
109
+
110
+ # =========================
111
+ # UI ROUTE
112
+ # =========================
113
 
114
  @app.get("/", response_class=HTMLResponse)
115
  async def home(request: Request):
116
+ return templates.TemplateResponse("index.html", {"request": request})
117
+
118
+
119
+ # =========================
120
+ # HEALTH CHECK
121
+ # =========================
122
+
123
+ @app.get("/health")
124
+ def health():
125
+ return {
126
+ "status": "ok",
127
+ "ollama": OLLAMA_URL,
128
+ "models": {
129
+ "default": OLLAMA_MODEL,
130
+ "code": OLLAMA_CODE_MODEL
131
+ }
132
+ }
133
+
134
+
135
+ # =========================
136
+ # CHAT ENDPOINT
137
+ # =========================
138
+
139
+ @app.post("/api/chat")
140
+ async def chat(request: Request):
141
+ body = await request.json()
142
+
143
+ prompt = body.get("prompt", "")
144
+ mode = body.get("mode", "default")
145
+
146
+ model = route_model(mode)
147
+
148
+ result = call_ollama(prompt, model)
149
+
150
+ # fallback logic
151
+ if "error" in result and OLLAMA_FALLBACK_URL:
152
+ try:
153
+ r = requests.post(
154
+ f"{OLLAMA_FALLBACK_URL}/api/generate",
155
+ json={
156
+ "model": OLLAMA_BACKUP_MODEL,
157
+ "prompt": prompt,
158
+ "stream": False
159
+ },
160
+ timeout=60
161
+ )
162
+ result = r.json()
163
+ except Exception as e:
164
+ result = {"error": str(e)}
165
+
166
+ return JSONResponse(result)
167
+
168
+
169
+ # =========================
170
+ # IMAGE PIPELINE HOOK (stub)
171
+ # =========================
172
+
173
+ @app.post("/api/image")
174
+ async def image_pipeline(request: Request):
175
+ body = await request.json()
176
+
177
+ prompt = body.get("prompt", "a modern hairstyle")
178
+
179
+ return {
180
+ "status": "queued",
181
+ "message": "Image pipeline not yet connected",
182
+ "prompt": prompt
183
+ }
184
+
185
+
186
+ # =========================
187
+ # N8N WEBHOOK TRIGGER
188
+ # =========================
189
+
190
+ @app.post("/api/webhook/n8n")
191
+ async def trigger_n8n(request: Request):
192
+ body = await request.json()
193
+
194
+ webhook_url = os.getenv("N8N_WEBHOOK_URL")
195
+
196
+ if not webhook_url:
197
+ return {"error": "No webhook configured"}
198
+
199
+ try:
200
+ r = requests.post(webhook_url, json=body, timeout=30)
201
+ return {"status": "sent", "response": r.text}
202
+ except Exception as e:
203
+ return {"error": str(e)}
204
+
205
+
206
+ # =========================
207
+ # DEBUG CONFIG (SAFE)
208
+ # =========================
209
+
210
+ @app.get("/config")
211
+ def config():
212
+ return {
213
+ "ollama_url": OLLAMA_URL,
214
+ "models": {
215
+ "default": OLLAMA_MODEL,
216
+ "code": OLLAMA_CODE_MODEL,
217
+ "fast": OLLAMA_FAST_MODEL,
218
+ "backup": OLLAMA_BACKUP_MODEL
219
+ },
220
+ "openrouter": {
221
+ "enabled": bool(OPENROUTER_API_KEY)
222
+ },
223
+ "supabase": {
224
+ "enabled": bool(SUPABASE_URL and SUPABASE_KEY)
225
+ }
226
+ }