FrederickSundeep commited on
Commit
0ab4c23
·
1 Parent(s): bce09f3

commit 0000002361

Browse files
Files changed (2) hide show
  1. app.py +68 -129
  2. requirements.txt +3 -3
app.py CHANGED
@@ -1,147 +1,86 @@
1
- from flask import Flask, request, jsonify, Response
2
- from flasgger import Swagger, swag_from
3
  import os
4
- import requests
 
 
 
5
  from dotenv import load_dotenv
6
 
7
  load_dotenv()
8
 
9
- app = Flask(__name__)
10
- swagger = Swagger(app)
 
 
 
11
 
12
- HF_TOKEN = os.environ.get("CHAT_MATE")
 
 
 
 
 
 
 
13
 
14
- @app.route("/chat-stream", methods=["POST"])
15
- @swag_from({
16
- 'tags': ['Chat'],
17
- 'consumes': ['application/json'],
18
- 'summary': 'Stream assistant reply or image',
19
- 'description': 'Send a message and history, receive either a streamed text reply or base64-encoded image.',
20
- 'parameters': [{
21
- 'name': 'body',
22
- 'in': 'body',
23
- 'required': True,
24
- 'schema': {
25
- 'type': 'object',
26
- 'properties': {
27
- 'message': {'type': 'string', 'example': 'Draw a futuristic city.'},
28
- 'history': {
29
- 'type': 'array',
30
- 'items': {
31
- 'type': 'object',
32
- 'properties': {
33
- 'role': {'type': 'string', 'example': 'user'},
34
- 'content': {'type': 'string', 'example': 'Show me a dragon.'}
35
- }
36
- }
37
- }
38
- },
39
- 'required': ['message']
40
- }
41
- }],
42
- 'responses': {
43
- 200: {
44
- 'description': 'Streamed reply or image base64',
45
- 'content': {'text/plain': {}}
46
- }
47
- }
48
- })
49
- def chat_stream():
50
- data = request.get_json()
51
- headers = {"Authorization": f"Bearer {HF_TOKEN}"}
52
- response = requests.post(
53
- "https://fredericksundeep-chatmateapi.hf.space/chat-stream",
54
- json=data,
55
- headers=headers,
56
- stream=True
57
- )
58
- return Response(response.iter_content(decode_unicode=True), mimetype="text/plain")
59
 
60
- @app.route("/chat-stream-doc", methods=["POST"])
61
- @swag_from({
62
- 'tags': ['Chat'],
63
- 'consumes': ['multipart/form-data'],
64
- 'summary': 'Upload requirement doc & generate downloadable project code (ZIP)',
65
- 'description': 'Upload a PDF/TXT requirement document with stack preferences, and receive the scaffolded project code as a downloadable .zip file.',
66
- 'parameters': [
67
- {
68
- 'name': 'file',
69
- 'in': 'formData',
70
- 'type': 'file',
71
- 'required': True,
72
- 'description': 'Requirement document (PDF or TXT)'
73
- },
74
- {
75
- 'name': 'frontend',
76
- 'in': 'formData',
77
- 'type': 'string',
78
- 'required': True,
79
- 'description': 'Frontend tech (React, Angular, etc.)'
80
- },
81
- {
82
- 'name': 'backend',
83
- 'in': 'formData',
84
- 'type': 'string',
85
- 'required': True,
86
- 'description': 'Backend tech (Flask, Node.js, etc.)'
87
- },
88
- {
89
- 'name': 'database',
90
- 'in': 'formData',
91
- 'type': 'string',
92
- 'required': True,
93
- 'description': 'Database (MongoDB, PostgreSQL, etc.)'
94
- }
95
- ],
96
- 'responses': {
97
- 200: {
98
- 'description': 'ZIP file of generated code',
99
- 'content': {'application/zip': {}}
100
- }
101
- }
102
- })
103
- def chat_stream_doc():
104
- from werkzeug.utils import secure_filename
105
 
106
- file = request.files.get("file")
107
- if not file:
108
- return jsonify({"error": "No file uploaded"}), 400
 
 
109
 
110
- filename = secure_filename(file.filename)
111
- frontend = request.form.get("frontend")
112
- backend = request.form.get("backend")
113
- database = request.form.get("database")
 
 
114
 
115
- headers = {
116
- "Authorization": f"Bearer {HF_TOKEN}"
117
- }
 
 
 
 
118
 
119
- files = {
120
- "file": (filename, file.stream, file.mimetype)
121
- }
122
 
123
- data = {
124
- "frontend": frontend,
125
- "backend": backend,
126
- "database": database
127
- }
 
 
 
 
 
 
 
 
 
128
 
129
- try:
130
- response = requests.post(
131
- "https://fredericksundeep-aimateapis.hf.space/chat-stream-doc",
132
- headers=headers,
133
- files=files,
134
- data=data
135
- )
136
 
137
- return (response.content, response.status_code, {
138
- "Content-Type": response.headers.get("Content-Type", "application/octet-stream"),
139
- "Content-Disposition": response.headers.get("Content-Disposition", "attachment; filename=generated_project.zip")
140
- })
 
 
 
 
141
 
142
- except Exception as e:
143
- return jsonify({"error": str(e)}), 500
144
 
145
  if __name__ == "__main__":
146
- print("🔧 Warming up...")
147
- app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))
 
 
 
 
1
  import os
2
+ import aiohttp
3
+ from fastapi import FastAPI, WebSocket, UploadFile, Form
4
+ from fastapi.responses import StreamingResponse, Response, JSONResponse
5
+ from fastapi.middleware.cors import CORSMiddleware
6
  from dotenv import load_dotenv
7
 
8
  load_dotenv()
9
 
10
+ app = FastAPI(
11
+ title="Public API Gateway",
12
+ description="Proxies requests from React → private backend securely",
13
+ version="1.0"
14
+ )
15
 
16
+ # Allow React frontend to call this API
17
+ app.add_middleware(
18
+ CORSMiddleware,
19
+ allow_origins=["*"], # you can restrict to your frontend domain
20
+ allow_credentials=True,
21
+ allow_methods=["*"],
22
+ allow_headers=["*"],
23
+ )
24
 
25
+ HF_TOKEN = os.environ.get("CHAT_MATE")
26
+ PRIVATE_HTTP_URL = "https://fredericksundeep-chatmateapi.hf.space/chat-stream"
27
+ PRIVATE_DOC_URL = "https://fredericksundeep-aimateapis.hf.space/chat-stream-doc"
28
+ PRIVATE_WS_URL = "wss://fredericksundeep-chatmateapi.hf.space/chat-stream"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ # Streaming text/images via WebSocket
32
+ @app.websocket("/chat-stream")
33
+ async def chat_stream(websocket: WebSocket):
34
+ await websocket.accept()
35
+ data = await websocket.receive_json()
36
 
37
+ async with aiohttp.ClientSession() as session:
38
+ async with session.ws_connect(
39
+ PRIVATE_WS_URL,
40
+ headers={"Authorization": f"Bearer {HF_TOKEN}"}
41
+ ) as private_ws:
42
+ await private_ws.send_json(data)
43
 
44
+ async for msg in private_ws:
45
+ if msg.type == aiohttp.WSMsgType.TEXT:
46
+ await websocket.send_text(msg.data)
47
+ elif msg.type == aiohttp.WSMsgType.BINARY:
48
+ await websocket.send_bytes(msg.data)
49
+ elif msg.type == aiohttp.WSMsgType.CLOSE:
50
+ break
51
 
 
 
 
52
 
53
+ # Handle file uploads for doc generation
54
+ @app.post("/chat-stream-doc")
55
+ async def chat_stream_doc(
56
+ file: UploadFile,
57
+ frontend: str = Form(...),
58
+ backend: str = Form(...),
59
+ database: str = Form(...)
60
+ ):
61
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
62
+ form_data = aiohttp.FormData()
63
+ form_data.add_field("file", file.file, filename=file.filename, content_type=file.content_type)
64
+ form_data.add_field("frontend", frontend)
65
+ form_data.add_field("backend", backend)
66
+ form_data.add_field("database", database)
67
 
68
+ async with aiohttp.ClientSession() as session:
69
+ async with session.post(PRIVATE_DOC_URL, data=form_data, headers=headers) as resp:
70
+ if resp.status != 200:
71
+ return JSONResponse({"error": await resp.text()}, status_code=resp.status)
 
 
 
72
 
73
+ # Stream ZIP file back to client
74
+ return Response(
75
+ content=await resp.read(),
76
+ media_type=resp.headers.get("Content-Type", "application/octet-stream"),
77
+ headers={
78
+ "Content-Disposition": "attachment; filename=generated_project.zip"
79
+ }
80
+ )
81
 
 
 
82
 
83
  if __name__ == "__main__":
84
+ import uvicorn
85
+ print("🚀 Starting FastAPI server...")
86
+ uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- flask
2
- flasgger
3
- requests
4
  python-dotenv
 
 
1
+ fastapi
2
+ uvicorn
 
3
  python-dotenv
4
+ requests