Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Upload folder using huggingface_hub
Browse files- main.py +6 -1
- pyproject.toml +1 -0
- requirements.txt +13 -11
- server.py +61 -1
- uv.lock +29 -1
main.py
CHANGED
|
@@ -13,11 +13,16 @@ import logging
|
|
| 13 |
from fastapi import Request
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
from fastapi.staticfiles import StaticFiles
|
| 16 |
-
|
|
|
|
|
|
|
| 17 |
|
| 18 |
logging.basicConfig(level=logging.INFO)
|
| 19 |
|
| 20 |
app = FastAPI(title="Sanatan AI Unified Server")
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
# Allow all origins (for dev)
|
| 23 |
app.add_middleware(
|
|
|
|
| 13 |
from fastapi import Request
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
from fastapi.staticfiles import StaticFiles
|
| 16 |
+
from slowapi import Limiter, _rate_limit_exceeded_handler
|
| 17 |
+
from slowapi.util import get_remote_address
|
| 18 |
+
from slowapi.errors import RateLimitExceeded
|
| 19 |
|
| 20 |
logging.basicConfig(level=logging.INFO)
|
| 21 |
|
| 22 |
app = FastAPI(title="Sanatan AI Unified Server")
|
| 23 |
+
limiter = Limiter(key_func=get_remote_address)
|
| 24 |
+
app.state.limiter = limiter
|
| 25 |
+
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
| 26 |
|
| 27 |
# Allow all origins (for dev)
|
| 28 |
app.add_middleware(
|
pyproject.toml
CHANGED
|
@@ -23,4 +23,5 @@ dependencies = [
|
|
| 23 |
"oauth2client>=4.1.3",
|
| 24 |
"pycountry>=24.6.1",
|
| 25 |
"sentence-transformers>=5.0.0",
|
|
|
|
| 26 |
]
|
|
|
|
| 23 |
"oauth2client>=4.1.3",
|
| 24 |
"pycountry>=24.6.1",
|
| 25 |
"sentence-transformers>=5.0.0",
|
| 26 |
+
"slowapi>=0.1.9",
|
| 27 |
]
|
requirements.txt
CHANGED
|
@@ -50,18 +50,14 @@ click==8.2.1
|
|
| 50 |
# via
|
| 51 |
# typer
|
| 52 |
# uvicorn
|
| 53 |
-
colorama==0.4.6
|
| 54 |
-
# via
|
| 55 |
-
# build
|
| 56 |
-
# click
|
| 57 |
-
# tqdm
|
| 58 |
-
# uvicorn
|
| 59 |
coloredlogs==15.0.1
|
| 60 |
# via onnxruntime
|
| 61 |
dataclasses-json==0.6.7
|
| 62 |
# via langchain-community
|
| 63 |
deprecated==1.2.18
|
| 64 |
-
# via
|
|
|
|
|
|
|
| 65 |
distro==1.9.0
|
| 66 |
# via
|
| 67 |
# openai
|
|
@@ -128,8 +124,6 @@ gradio-client==1.13.1
|
|
| 128 |
# via gradio
|
| 129 |
gradio-modal==0.0.4
|
| 130 |
# via sanatan-ai (pyproject.toml)
|
| 131 |
-
greenlet==3.2.3
|
| 132 |
-
# via sqlalchemy
|
| 133 |
groovy==0.1.2
|
| 134 |
# via gradio
|
| 135 |
grpcio==1.74.0
|
|
@@ -142,6 +136,8 @@ h11==0.16.0
|
|
| 142 |
# via
|
| 143 |
# httpcore
|
| 144 |
# uvicorn
|
|
|
|
|
|
|
| 145 |
httpcore==1.0.9
|
| 146 |
# via httpx
|
| 147 |
httplib2==0.22.0
|
|
@@ -241,6 +237,8 @@ language-data==1.3.0
|
|
| 241 |
# via
|
| 242 |
# aksharamukha
|
| 243 |
# langcodes
|
|
|
|
|
|
|
| 244 |
lxml==6.0.2
|
| 245 |
# via aksharamukha
|
| 246 |
marisa-trie==1.3.1
|
|
@@ -325,6 +323,7 @@ packaging==25.0
|
|
| 325 |
# huggingface-hub
|
| 326 |
# langchain-core
|
| 327 |
# langsmith
|
|
|
|
| 328 |
# marshmallow
|
| 329 |
# onnxruntime
|
| 330 |
# transformers
|
|
@@ -391,8 +390,6 @@ pypika==0.48.9
|
|
| 391 |
# via chromadb
|
| 392 |
pyproject-hooks==1.2.0
|
| 393 |
# via build
|
| 394 |
-
pyreadline3==3.5.4
|
| 395 |
-
# via humanfriendly
|
| 396 |
python-dateutil==2.9.0.post0
|
| 397 |
# via
|
| 398 |
# kubernetes
|
|
@@ -491,6 +488,8 @@ six==1.17.0
|
|
| 491 |
# posthog
|
| 492 |
# python-dateutil
|
| 493 |
# stone
|
|
|
|
|
|
|
| 494 |
sniffio==1.3.1
|
| 495 |
# via
|
| 496 |
# anyio
|
|
@@ -547,6 +546,7 @@ typing-extensions==4.14.1
|
|
| 547 |
# gradio-client
|
| 548 |
# huggingface-hub
|
| 549 |
# langchain-core
|
|
|
|
| 550 |
# openai
|
| 551 |
# opentelemetry-api
|
| 552 |
# opentelemetry-exporter-otlp-proto-grpc
|
|
@@ -578,6 +578,8 @@ uvicorn==0.35.0
|
|
| 578 |
# via
|
| 579 |
# chromadb
|
| 580 |
# gradio
|
|
|
|
|
|
|
| 581 |
watchfiles==1.1.0
|
| 582 |
# via uvicorn
|
| 583 |
websocket-client==1.8.0
|
|
|
|
| 50 |
# via
|
| 51 |
# typer
|
| 52 |
# uvicorn
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
coloredlogs==15.0.1
|
| 54 |
# via onnxruntime
|
| 55 |
dataclasses-json==0.6.7
|
| 56 |
# via langchain-community
|
| 57 |
deprecated==1.2.18
|
| 58 |
+
# via
|
| 59 |
+
# limits
|
| 60 |
+
# pykakasi
|
| 61 |
distro==1.9.0
|
| 62 |
# via
|
| 63 |
# openai
|
|
|
|
| 124 |
# via gradio
|
| 125 |
gradio-modal==0.0.4
|
| 126 |
# via sanatan-ai (pyproject.toml)
|
|
|
|
|
|
|
| 127 |
groovy==0.1.2
|
| 128 |
# via gradio
|
| 129 |
grpcio==1.74.0
|
|
|
|
| 136 |
# via
|
| 137 |
# httpcore
|
| 138 |
# uvicorn
|
| 139 |
+
hf-xet==1.2.0
|
| 140 |
+
# via huggingface-hub
|
| 141 |
httpcore==1.0.9
|
| 142 |
# via httpx
|
| 143 |
httplib2==0.22.0
|
|
|
|
| 237 |
# via
|
| 238 |
# aksharamukha
|
| 239 |
# langcodes
|
| 240 |
+
limits==5.6.0
|
| 241 |
+
# via slowapi
|
| 242 |
lxml==6.0.2
|
| 243 |
# via aksharamukha
|
| 244 |
marisa-trie==1.3.1
|
|
|
|
| 323 |
# huggingface-hub
|
| 324 |
# langchain-core
|
| 325 |
# langsmith
|
| 326 |
+
# limits
|
| 327 |
# marshmallow
|
| 328 |
# onnxruntime
|
| 329 |
# transformers
|
|
|
|
| 390 |
# via chromadb
|
| 391 |
pyproject-hooks==1.2.0
|
| 392 |
# via build
|
|
|
|
|
|
|
| 393 |
python-dateutil==2.9.0.post0
|
| 394 |
# via
|
| 395 |
# kubernetes
|
|
|
|
| 488 |
# posthog
|
| 489 |
# python-dateutil
|
| 490 |
# stone
|
| 491 |
+
slowapi==0.1.9
|
| 492 |
+
# via sanatan-ai (pyproject.toml)
|
| 493 |
sniffio==1.3.1
|
| 494 |
# via
|
| 495 |
# anyio
|
|
|
|
| 546 |
# gradio-client
|
| 547 |
# huggingface-hub
|
| 548 |
# langchain-core
|
| 549 |
+
# limits
|
| 550 |
# openai
|
| 551 |
# opentelemetry-api
|
| 552 |
# opentelemetry-exporter-otlp-proto-grpc
|
|
|
|
| 578 |
# via
|
| 579 |
# chromadb
|
| 580 |
# gradio
|
| 581 |
+
uvloop==0.22.1
|
| 582 |
+
# via uvicorn
|
| 583 |
watchfiles==1.1.0
|
| 584 |
# via uvicorn
|
| 585 |
websocket-client==1.8.0
|
server.py
CHANGED
|
@@ -20,9 +20,18 @@ from modules.quiz.answer_validator import validate_answer
|
|
| 20 |
from modules.quiz.models import Question
|
| 21 |
from modules.quiz.quiz_helper import generate_question
|
| 22 |
import logging
|
| 23 |
-
|
| 24 |
from modules.video.model import VideoRequest
|
| 25 |
from modules.video.service import svc_get_video_urls
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
logging.basicConfig()
|
| 28 |
logger = logging.getLogger(__name__)
|
|
@@ -627,3 +636,54 @@ async def get_discourse_detail(topic_id: int):
|
|
| 627 |
if not topic:
|
| 628 |
raise HTTPException(status_code=404, detail="Discourse topic not found")
|
| 629 |
return topic
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
from modules.quiz.models import Question
|
| 21 |
from modules.quiz.quiz_helper import generate_question
|
| 22 |
import logging
|
|
|
|
| 23 |
from modules.video.model import VideoRequest
|
| 24 |
from modules.video.service import svc_get_video_urls
|
| 25 |
+
from openai import OpenAI
|
| 26 |
+
from dotenv import load_dotenv
|
| 27 |
+
from slowapi.util import get_remote_address
|
| 28 |
+
from slowapi import Limiter
|
| 29 |
+
from slowapi.errors import RateLimitExceeded
|
| 30 |
+
|
| 31 |
+
router = APIRouter()
|
| 32 |
+
limiter = Limiter(key_func=get_remote_address)
|
| 33 |
+
|
| 34 |
+
load_dotenv()
|
| 35 |
|
| 36 |
logging.basicConfig()
|
| 37 |
logger = logging.getLogger(__name__)
|
|
|
|
| 636 |
if not topic:
|
| 637 |
raise HTTPException(status_code=404, detail="Discourse topic not found")
|
| 638 |
return topic
|
| 639 |
+
|
| 640 |
+
class TranslationRequest(BaseModel):
|
| 641 |
+
context : str
|
| 642 |
+
text: str
|
| 643 |
+
target_lang: str
|
| 644 |
+
|
| 645 |
+
client = OpenAI()
|
| 646 |
+
|
| 647 |
+
@router.post("/translate")
|
| 648 |
+
@limiter.limit("5/minute")
|
| 649 |
+
async def translate_text(request: Request, body: TranslationRequest):
|
| 650 |
+
"""
|
| 651 |
+
Translate text from any language (auto-detected) to the target language.
|
| 652 |
+
"""
|
| 653 |
+
try:
|
| 654 |
+
prompt = f"""
|
| 655 |
+
You are a professional translation engine that performs **literal, direct translations** — not summaries or interpretations.
|
| 656 |
+
|
| 657 |
+
Your objectives:
|
| 658 |
+
1. **Detect the source language and script automatically.**
|
| 659 |
+
2. If the source and target languages are the same ({body.target_lang}), return the original text unchanged.
|
| 660 |
+
3. Translate **each sentence or line** in a one-to-one manner, preserving structure, order, and approximate length.
|
| 661 |
+
4. Do **not infer**, **do not summarize**, and **do not paraphrase** — translate only what is written.
|
| 662 |
+
5. Maintain every phrase and symbol; do not omit or merge content.
|
| 663 |
+
6. If the input text appears to be **transliterated** (for example, Indic or Dravidian language text written in Latin characters), internally interpret it as its likely original language (e.g., Sanskrit, Tamil, Telugu, etc.) before translating to {body.target_lang}.
|
| 664 |
+
7. When the target language uses a non-Latin script, **output in that native script** (not in transliteration).
|
| 665 |
+
8. Use the provided context only to resolve ambiguity — never to alter, shorten, or elaborate the meaning.
|
| 666 |
+
9. Respond with **only the translated text** — no commentary, explanations, transliterations, or formatting.
|
| 667 |
+
|
| 668 |
+
Context (for disambiguation only):
|
| 669 |
+
{body.context}
|
| 670 |
+
|
| 671 |
+
Text to translate:
|
| 672 |
+
{body.text}
|
| 673 |
+
"""
|
| 674 |
+
|
| 675 |
+
|
| 676 |
+
|
| 677 |
+
print(f"prompt = {prompt}")
|
| 678 |
+
|
| 679 |
+
response = client.chat.completions.create(
|
| 680 |
+
model="gpt-4o-mini",
|
| 681 |
+
messages=[{"role": "user", "content": prompt}],
|
| 682 |
+
temperature=0.2,
|
| 683 |
+
)
|
| 684 |
+
|
| 685 |
+
translation = response.choices[0].message.content.strip()
|
| 686 |
+
return {"translated_text": translation}
|
| 687 |
+
|
| 688 |
+
except Exception as e:
|
| 689 |
+
raise HTTPException(status_code=500, detail=str(e))
|
uv.lock
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
version = 1
|
| 2 |
-
revision =
|
| 3 |
requires-python = ">=3.12"
|
| 4 |
resolution-markers = [
|
| 5 |
"python_full_version >= '3.13'",
|
|
@@ -1400,6 +1400,20 @@ wheels = [
|
|
| 1400 |
{ url = "https://files.pythonhosted.org/packages/5d/e9/5a5ffd9b286db82be70d677d0a91e4d58f7912bb8dd026ddeeb4abe70679/language_data-1.3.0-py3-none-any.whl", hash = "sha256:e2ee943551b5ae5f89cd0e801d1fc3835bb0ef5b7e9c3a4e8e17b2b214548fbf", size = 5385760, upload-time = "2024-11-19T10:21:36.005Z" },
|
| 1401 |
]
|
| 1402 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1403 |
[[package]]
|
| 1404 |
name = "lxml"
|
| 1405 |
version = "6.0.2"
|
|
@@ -3070,6 +3084,7 @@ dependencies = [
|
|
| 3070 |
{ name = "oauth2client" },
|
| 3071 |
{ name = "pycountry" },
|
| 3072 |
{ name = "sentence-transformers" },
|
|
|
|
| 3073 |
]
|
| 3074 |
|
| 3075 |
[package.metadata]
|
|
@@ -3092,6 +3107,7 @@ requires-dist = [
|
|
| 3092 |
{ name = "oauth2client", specifier = ">=4.1.3" },
|
| 3093 |
{ name = "pycountry", specifier = ">=24.6.1" },
|
| 3094 |
{ name = "sentence-transformers", specifier = ">=5.0.0" },
|
|
|
|
| 3095 |
]
|
| 3096 |
|
| 3097 |
[[package]]
|
|
@@ -3250,6 +3266,18 @@ wheels = [
|
|
| 3250 |
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
| 3251 |
]
|
| 3252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3253 |
[[package]]
|
| 3254 |
name = "sniffio"
|
| 3255 |
version = "1.3.1"
|
|
|
|
| 1 |
version = 1
|
| 2 |
+
revision = 3
|
| 3 |
requires-python = ">=3.12"
|
| 4 |
resolution-markers = [
|
| 5 |
"python_full_version >= '3.13'",
|
|
|
|
| 1400 |
{ url = "https://files.pythonhosted.org/packages/5d/e9/5a5ffd9b286db82be70d677d0a91e4d58f7912bb8dd026ddeeb4abe70679/language_data-1.3.0-py3-none-any.whl", hash = "sha256:e2ee943551b5ae5f89cd0e801d1fc3835bb0ef5b7e9c3a4e8e17b2b214548fbf", size = 5385760, upload-time = "2024-11-19T10:21:36.005Z" },
|
| 1401 |
]
|
| 1402 |
|
| 1403 |
+
[[package]]
|
| 1404 |
+
name = "limits"
|
| 1405 |
+
version = "5.6.0"
|
| 1406 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1407 |
+
dependencies = [
|
| 1408 |
+
{ name = "deprecated" },
|
| 1409 |
+
{ name = "packaging" },
|
| 1410 |
+
{ name = "typing-extensions" },
|
| 1411 |
+
]
|
| 1412 |
+
sdist = { url = "https://files.pythonhosted.org/packages/bb/e5/c968d43a65128cd54fb685f257aafb90cd5e4e1c67d084a58f0e4cbed557/limits-5.6.0.tar.gz", hash = "sha256:807fac75755e73912e894fdd61e2838de574c5721876a19f7ab454ae1fffb4b5", size = 182984, upload-time = "2025-09-29T17:15:22.689Z" }
|
| 1413 |
+
wheels = [
|
| 1414 |
+
{ url = "https://files.pythonhosted.org/packages/40/96/4fcd44aed47b8fcc457653b12915fcad192cd646510ef3f29fd216f4b0ab/limits-5.6.0-py3-none-any.whl", hash = "sha256:b585c2104274528536a5b68864ec3835602b3c4a802cd6aa0b07419798394021", size = 60604, upload-time = "2025-09-29T17:15:18.419Z" },
|
| 1415 |
+
]
|
| 1416 |
+
|
| 1417 |
[[package]]
|
| 1418 |
name = "lxml"
|
| 1419 |
version = "6.0.2"
|
|
|
|
| 3084 |
{ name = "oauth2client" },
|
| 3085 |
{ name = "pycountry" },
|
| 3086 |
{ name = "sentence-transformers" },
|
| 3087 |
+
{ name = "slowapi" },
|
| 3088 |
]
|
| 3089 |
|
| 3090 |
[package.metadata]
|
|
|
|
| 3107 |
{ name = "oauth2client", specifier = ">=4.1.3" },
|
| 3108 |
{ name = "pycountry", specifier = ">=24.6.1" },
|
| 3109 |
{ name = "sentence-transformers", specifier = ">=5.0.0" },
|
| 3110 |
+
{ name = "slowapi", specifier = ">=0.1.9" },
|
| 3111 |
]
|
| 3112 |
|
| 3113 |
[[package]]
|
|
|
|
| 3266 |
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
| 3267 |
]
|
| 3268 |
|
| 3269 |
+
[[package]]
|
| 3270 |
+
name = "slowapi"
|
| 3271 |
+
version = "0.1.9"
|
| 3272 |
+
source = { registry = "https://pypi.org/simple" }
|
| 3273 |
+
dependencies = [
|
| 3274 |
+
{ name = "limits" },
|
| 3275 |
+
]
|
| 3276 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a0/99/adfc7f94ca024736f061257d39118e1542bade7a52e86415a4c4ae92d8ff/slowapi-0.1.9.tar.gz", hash = "sha256:639192d0f1ca01b1c6d95bf6c71d794c3a9ee189855337b4821f7f457dddad77", size = 14028, upload-time = "2024-02-05T12:11:52.13Z" }
|
| 3277 |
+
wheels = [
|
| 3278 |
+
{ url = "https://files.pythonhosted.org/packages/2b/bb/f71c4b7d7e7eb3fc1e8c0458a8979b912f40b58002b9fbf37729b8cb464b/slowapi-0.1.9-py3-none-any.whl", hash = "sha256:cfad116cfb84ad9d763ee155c1e5c5cbf00b0d47399a769b227865f5df576e36", size = 14670, upload-time = "2024-02-05T12:11:50.898Z" },
|
| 3279 |
+
]
|
| 3280 |
+
|
| 3281 |
[[package]]
|
| 3282 |
name = "sniffio"
|
| 3283 |
version = "1.3.1"
|