vikramvasudevan commited on
Commit
1a9eef9
·
verified ·
1 Parent(s): ed3d515

Upload folder using huggingface_hub

Browse files
Files changed (5) hide show
  1. main.py +6 -1
  2. pyproject.toml +1 -0
  3. requirements.txt +13 -11
  4. server.py +61 -1
  5. 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 pykakasi
 
 
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 = 2
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"