alaselababatunde commited on
Commit
f51917e
·
1 Parent(s): 7b32b5c
Files changed (1) hide show
  1. main.py +77 -56
main.py CHANGED
@@ -7,11 +7,11 @@ from spitch import Spitch
7
  from langchain.prompts import PromptTemplate
8
  from langchain_huggingface import HuggingFaceEndpoint
9
  from langdetect import detect, DetectorFactory
10
- from huggingface_hub.utils import HfHubHTTPError # for quota error handling
11
 
 
12
  DetectorFactory.seed = 0
13
 
14
- # --------- BASIC CONFIG ----------
15
  SPITCH_API_KEY = os.getenv("SPITCH_API_KEY")
16
  HF_MODEL = os.getenv("HF_MODEL", "google/flan-t5-base")
17
  FRONTEND_ORIGIN = os.getenv("ALLOWED_ORIGIN", "*")
@@ -24,7 +24,7 @@ if not SPITCH_API_KEY:
24
  os.environ["SPITCH_API_KEY"] = SPITCH_API_KEY
25
  spitch_client = Spitch()
26
 
27
- # HuggingFaceEndpoint
28
  llm = HuggingFaceEndpoint(
29
  repo_id=HF_MODEL,
30
  temperature=0.2,
@@ -43,7 +43,7 @@ app.add_middleware(
43
  allow_headers=["Authorization", "Content-Type"],
44
  )
45
 
46
- # --------- PROMPT TEMPLATES ----------
47
  chat_template = """You are DevAssist, an AI coding assistant.
48
 
49
  Guidelines:
@@ -59,40 +59,43 @@ Question: {question}
59
  Answer:
60
  """
61
 
62
-
63
  stt_chat_template = """You are DevAssist, an AI coding assistant.
64
  - The input is transcribed speech. Interpret it as a dev question.
65
  - Provide clear answers with code examples (use markdown triple backticks).
66
  - If input is unclear, ask a clarifying question.
 
67
  Spoken Question: {speech}
68
- Answer:"""
 
69
 
70
  autodoc_template = """You are DevAssist DocBot.
71
  - Read the code and produce professional documentation in markdown.
 
72
  Code: {code}
73
- Documentation:"""
 
74
 
75
  sme_template = """
76
  You are an SME site builder AI.
77
  Your job is to turn ANY user prompt (simple or complex) into a working, modern web project.
78
  You must analyze the request carefully and generate clean, professional, and responsive code.
79
 
80
- 🔑 Rules:
81
  1. Always return ONLY valid JSON (no explanations, no Markdown).
82
  2. Always include "index.html", "style.css", and "script.js" in the "files".
83
- 3. Support multiple pages if the user specifies them in the request.
84
  4. Style must be modern, vibrant, and responsive:
85
- - Use semantic HTML5 structure (<header>, <main>, <section>, <footer>).
86
- - Use CSS with modern fonts, colors, spacing, hover effects, flex/grid layout.
87
  - Buttons must be styled and interactive.
88
  - Add responsiveness for mobile.
89
  5. Translate vague descriptions like “make it futuristic and sharp” into concrete CSS design choices.
90
- 6. If the user’s request is very detailed, honor as much as possible while still keeping valid code.
91
 
92
  User Prompt:
93
  {user_prompt}
94
 
95
- Return ONLY JSON in this exact format:
96
  {
97
  "files": {
98
  "index.html": "<!DOCTYPE html> ... </html>",
@@ -103,29 +106,20 @@ Return ONLY JSON in this exact format:
103
  }
104
  """
105
 
 
 
 
 
 
106
 
107
- # --------- CHAINS ----------
108
- chat_prompt = PromptTemplate(input_variables=["question"], template=chat_template)
109
- stt_prompt = PromptTemplate(input_variables=["speech"], template=stt_chat_template)
110
- autodoc_prompt = PromptTemplate(input_variables=["code"], template=autodoc_template)
111
- sme_prompt = PromptTemplate(
112
- input_variables=["site_name", "stack", "pages", "language"],
113
- template=sme_template
114
- )
115
-
116
- chat_chain = chat_prompt | llm
117
- stt_chain = stt_prompt | llm
118
- autodoc_chain = autodoc_prompt | llm
119
- sme_chain = sme_prompt | llm
120
-
121
- # --------- REQUEST MODELS ----------
122
  class ChatRequest(BaseModel):
123
  question: str
124
 
125
  class AutoDocRequest(BaseModel):
126
  code: str
127
 
128
- # --------- AUTH ----------
129
  def check_auth(authorization: str | None):
130
  if not PROJECT_API_KEY:
131
  return
@@ -135,7 +129,7 @@ def check_auth(authorization: str | None):
135
  if token != PROJECT_API_KEY:
136
  raise HTTPException(status_code=403, detail="Invalid token")
137
 
138
- # --------- ENDPOINTS ----------
139
  @app.get("/")
140
  def root():
141
  return {"status": "DevAssist AI Backend running"}
@@ -148,9 +142,7 @@ def chat(req: ChatRequest, authorization: str | None = Header(None)):
148
  return {"reply": answer.strip() if isinstance(answer, str) else str(answer)}
149
  except HfHubHTTPError as e:
150
  if "exceeded" in str(e).lower() or "quota" in str(e).lower():
151
- return {
152
- "reply": "⚠️ You have reached your daily limit for reponses today. Please come back in 24 hours."
153
- }
154
  raise e
155
 
156
  @app.post("/stt")
@@ -171,7 +163,7 @@ async def stt_audio(file: UploadFile = File(...), lang_hint: str | None = None,
171
  except Exception:
172
  resp = spitch_client.speech.transcribe(language="en", content=open(tmp_path, "rb").read())
173
 
174
- transcription = getattr(resp, "text", "") or resp.get("text", "") if isinstance(resp, dict) else ""
175
 
176
  try:
177
  detected_lang = detect(transcription) if transcription.strip() else "en"
@@ -182,7 +174,7 @@ async def stt_audio(file: UploadFile = File(...), lang_hint: str | None = None,
182
  if detected_lang != "en":
183
  try:
184
  translation_resp = spitch_client.text.translate(text=transcription, source=detected_lang, target="en")
185
- translation = getattr(translation_resp, "text", "") or translation_resp.get("text", "") if isinstance(translation_resp, dict) else translation
186
  except Exception:
187
  translation = transcription
188
 
@@ -203,33 +195,62 @@ def autodoc(req: AutoDocRequest, authorization: str | None = Header(None)):
203
 
204
  @app.post("/sme/generate")
205
  async def sme_generate(payload: dict = Body(...)):
206
- """
207
- Generate SME site boilerplate.
208
- Expected payload:
209
- {
210
- "site_name": "...",
211
- "stack": "react"|"html-css-js",
212
- "pages": [{ "name": "home", "content": "..." }],
213
- "language": "en"
214
- }
215
- """
216
  try:
217
- response = sme_chain.invoke({
218
- "site_name": payload.get("site_name"),
219
- "stack": payload.get("stack"),
220
- "pages": payload.get("pages"),
221
- "language": payload.get("language"),
222
- })
223
  return {"success": True, "data": response}
224
  except HfHubHTTPError as e:
225
  if "exceeded" in str(e).lower() or "quota" in str(e).lower():
226
- return {
227
- "success": False,
228
- "error": "⚠️ Token quota for today has been used. Please come back in 24 hours."
229
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  raise e
231
 
232
- # Hugging Face requires port 7860, not 8000
233
  if __name__ == "__main__":
234
  import uvicorn
235
  uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=False)
 
7
  from langchain.prompts import PromptTemplate
8
  from langchain_huggingface import HuggingFaceEndpoint
9
  from langdetect import detect, DetectorFactory
10
+ from huggingface_hub.utils import HfHubHTTPError # for quota error handling
11
 
12
+ # ----------------- CONFIG -----------------
13
  DetectorFactory.seed = 0
14
 
 
15
  SPITCH_API_KEY = os.getenv("SPITCH_API_KEY")
16
  HF_MODEL = os.getenv("HF_MODEL", "google/flan-t5-base")
17
  FRONTEND_ORIGIN = os.getenv("ALLOWED_ORIGIN", "*")
 
24
  os.environ["SPITCH_API_KEY"] = SPITCH_API_KEY
25
  spitch_client = Spitch()
26
 
27
+ # HuggingFace LLM
28
  llm = HuggingFaceEndpoint(
29
  repo_id=HF_MODEL,
30
  temperature=0.2,
 
43
  allow_headers=["Authorization", "Content-Type"],
44
  )
45
 
46
+ # ----------------- PROMPT TEMPLATES -----------------
47
  chat_template = """You are DevAssist, an AI coding assistant.
48
 
49
  Guidelines:
 
59
  Answer:
60
  """
61
 
 
62
  stt_chat_template = """You are DevAssist, an AI coding assistant.
63
  - The input is transcribed speech. Interpret it as a dev question.
64
  - Provide clear answers with code examples (use markdown triple backticks).
65
  - If input is unclear, ask a clarifying question.
66
+
67
  Spoken Question: {speech}
68
+ Answer:
69
+ """
70
 
71
  autodoc_template = """You are DevAssist DocBot.
72
  - Read the code and produce professional documentation in markdown.
73
+
74
  Code: {code}
75
+ Documentation:
76
+ """
77
 
78
  sme_template = """
79
  You are an SME site builder AI.
80
  Your job is to turn ANY user prompt (simple or complex) into a working, modern web project.
81
  You must analyze the request carefully and generate clean, professional, and responsive code.
82
 
83
+ Rules:
84
  1. Always return ONLY valid JSON (no explanations, no Markdown).
85
  2. Always include "index.html", "style.css", and "script.js" in the "files".
86
+ 3. Support multiple pages if the user specifies them.
87
  4. Style must be modern, vibrant, and responsive:
88
+ - Use semantic HTML5 (<header>, <main>, <section>, <footer>).
89
+ - Use CSS with modern fonts, colors, spacing, hover effects, flex/grid.
90
  - Buttons must be styled and interactive.
91
  - Add responsiveness for mobile.
92
  5. Translate vague descriptions like “make it futuristic and sharp” into concrete CSS design choices.
93
+ 6. If the request is very detailed, honor as much as possible while still keeping valid code.
94
 
95
  User Prompt:
96
  {user_prompt}
97
 
98
+ Return ONLY JSON in this format:
99
  {
100
  "files": {
101
  "index.html": "<!DOCTYPE html> ... </html>",
 
106
  }
107
  """
108
 
109
+ # ----------------- CHAINS -----------------
110
+ chat_chain = PromptTemplate(input_variables=["question"], template=chat_template) | llm
111
+ stt_chain = PromptTemplate(input_variables=["speech"], template=stt_chat_template) | llm
112
+ autodoc_chain = PromptTemplate(input_variables=["code"], template=autodoc_template) | llm
113
+ sme_chain = PromptTemplate(input_variables=["user_prompt"], template=sme_template) | llm
114
 
115
+ # ----------------- REQUEST MODELS -----------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  class ChatRequest(BaseModel):
117
  question: str
118
 
119
  class AutoDocRequest(BaseModel):
120
  code: str
121
 
122
+ # ----------------- AUTH -----------------
123
  def check_auth(authorization: str | None):
124
  if not PROJECT_API_KEY:
125
  return
 
129
  if token != PROJECT_API_KEY:
130
  raise HTTPException(status_code=403, detail="Invalid token")
131
 
132
+ # ----------------- ENDPOINTS -----------------
133
  @app.get("/")
134
  def root():
135
  return {"status": "DevAssist AI Backend running"}
 
142
  return {"reply": answer.strip() if isinstance(answer, str) else str(answer)}
143
  except HfHubHTTPError as e:
144
  if "exceeded" in str(e).lower() or "quota" in str(e).lower():
145
+ return {"reply": "⚠️ You have reached your daily limit for responses. Please come back in 24 hours."}
 
 
146
  raise e
147
 
148
  @app.post("/stt")
 
163
  except Exception:
164
  resp = spitch_client.speech.transcribe(language="en", content=open(tmp_path, "rb").read())
165
 
166
+ transcription = getattr(resp, "text", "") or (resp.get("text", "") if isinstance(resp, dict) else "")
167
 
168
  try:
169
  detected_lang = detect(transcription) if transcription.strip() else "en"
 
174
  if detected_lang != "en":
175
  try:
176
  translation_resp = spitch_client.text.translate(text=transcription, source=detected_lang, target="en")
177
+ translation = getattr(translation_resp, "text", "") or translation_resp.get("text", "")
178
  except Exception:
179
  translation = transcription
180
 
 
195
 
196
  @app.post("/sme/generate")
197
  async def sme_generate(payload: dict = Body(...)):
 
 
 
 
 
 
 
 
 
 
198
  try:
199
+ response = sme_chain.invoke({"user_prompt": payload.get("user_prompt", "")})
 
 
 
 
 
200
  return {"success": True, "data": response}
201
  except HfHubHTTPError as e:
202
  if "exceeded" in str(e).lower() or "quota" in str(e).lower():
203
+ return {"success": False, "error": "⚠️ Token quota for today has been used. Please come back in 24 hours."}
204
+ raise e
205
+
206
+ @app.post("/sme/speech-generate")
207
+ async def sme_speech_generate(file: UploadFile = File(...), lang_hint: str | None = None, authorization: str | None = Header(None)):
208
+ check_auth(authorization)
209
+
210
+ suffix = os.path.splitext(file.filename)[1] or ".wav"
211
+ with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tf:
212
+ content = await file.read()
213
+ tf.write(content)
214
+ tmp_path = tf.name
215
+
216
+ try:
217
+ if lang_hint:
218
+ resp = spitch_client.speech.transcribe(language=lang_hint, content=open(tmp_path, "rb").read())
219
+ else:
220
+ resp = spitch_client.speech.transcribe(content=open(tmp_path, "rb").read())
221
+ except Exception:
222
+ resp = spitch_client.speech.transcribe(language="en", content=open(tmp_path, "rb").read())
223
+
224
+ transcription = getattr(resp, "text", "") or (resp.get("text", "") if isinstance(resp, dict) else "")
225
+
226
+ try:
227
+ detected_lang = detect(transcription) if transcription.strip() else "en"
228
+ except Exception:
229
+ detected_lang = "en"
230
+
231
+ translation = transcription
232
+ if detected_lang != "en":
233
+ try:
234
+ translation_resp = spitch_client.text.translate(text=transcription, source=detected_lang, target="en")
235
+ translation = getattr(translation_resp, "text", "") or translation_resp.get("text", "")
236
+ except Exception:
237
+ translation = transcription
238
+
239
+ try:
240
+ sme_response = sme_chain.invoke({"user_prompt": translation})
241
+ return {
242
+ "success": True,
243
+ "transcription": transcription,
244
+ "detected_language": detected_lang,
245
+ "translation": translation,
246
+ "sme_site": sme_response
247
+ }
248
+ except HfHubHTTPError as e:
249
+ if "exceeded" in str(e).lower() or "quota" in str(e).lower():
250
+ return {"success": False, "error": "⚠️ Token quota for today has been used. Please come back in 24 hours."}
251
  raise e
252
 
253
+ # Hugging Face requires port 7860
254
  if __name__ == "__main__":
255
  import uvicorn
256
  uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=False)