from fastapi import FastAPI, Request, Query import src.Paraphrase as Paraphrase import src.Translate from typing import Optional from fastapi_mcp import FastApiMCP from huggingface_hub import hf_hub_download, list_repo_files from sentence_transformers import SentenceTransformer import bergamot app = FastAPI() # app = FastAPI(docs_url="/docs") MODELS = {'benro': 'BlackKakapo/opus-mt-en-ro', 'broen': 'BlackKakapo/opus-mt-ro-en', 'mttcbig': 'Helsinki-NLP/opus-mt-tc-big-en-ro', 'gemma': 'Gargaz/gemma-2b-romanian-better', 'mbartenro': 'ancebuc/mbart-translation-en-ro', 't5enro': 'ancebuc/t5-translation-en-ro', 'pegasus': 'ancebuc/pegasus-translation-en-ro', 'mbart': 'facebook/mbart-large-cc25', 'paraphrase': 'tuner007/pegasus_paraphrase'} EMBEDDING_MODELS = {"all-MiniLM-L6-v2":384, "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2":384, "sentence-transformers/distiluse-base-multilingual-cased-v2":512, "sentence-transformers/stsb-xlm-r-multilingual":768, "sentence-transformers/use-cmlm-multilingual":768, "sentence-transformers/paraphrase-multilingual-mpnet-base-v2":768} EMBEDDING_MODEL = "sentence-transformers/distiluse-base-multilingual-cased-v2" @app.get("/") def index(request: Request): from fastapi.responses import HTMLResponse host_url = "https://" + request.url.netloc mcp_config = '''{"mcpServers": {"fastapi-mcp": {"url": "https://tiberiucristianleon-fastapimt.hf.space/mcp"}}}''' html_content = f''' FastAPI with MCP

FastAPI URLS

Host URL: {host_url}

DOCS

REDOC

openapi.json

MCP

MCP configuration: {mcp_config}

MODELS: {list(MODELS.values())}"

''' return HTMLResponse(content=html_content) # @app.get("/") # async def get_host_url(request: Request): # host_url = request.url.scheme + "s://" + request.url.netloc # return {"host_url": host_url, 'endpoints': ['/paraphrase', '/translate', f'{host_url}/docs', f'{host_url}/redoc', f'{host_url}/openapi.json'], 'models': MODELS} @app.get("/paraphrase", operation_id="get_paraphrase", description="Paraphrase text", tags=["paraphrase"], summary="Paraphrase text") def paraphrase(text: str, model: str = MODELS['paraphrase']): resultValue, exception = Paraphrase.paraphraseParaphraseMethod(text, model) return {"input": text, "result": resultValue, "exception": exception} @app.get("/listmodels", operation_id="list_models", description="List models", tags=["listmodels"], summary="List models") def listmodels(): return {"MODELS": MODELS, "EMBEDDING_MODELS": EMBEDDING_MODELS} # model: Optional[str] = MODELS['benro'] @app.get("/translate", operation_id="get_translate", description="Translate text", tags=["translate"], summary="Translate text") def translate(input_text: str, model_name: str = MODELS['mttcbig'], sl: str = 'en', tl: str = 'ro'): message = f'Translated from {sl} to {tl} with {model_name}' if 'BlackKakapo' in model_name: translation, model_name = src.Translate.paraphraseTranslateMethod(input_text, model_name) elif 'Helsinki-NLP' in model_name: translation, message = src.Translate.Translators(model_name, sl, tl, input_text).HelsinkiNLP_mulroa() # text2textgenerationpipe, translationpipe # elif model_name == MODELS['mbartenro']: # translation, message = src.Translate.Translators(model_name, sl, tl, input_text).text2textgenerationpipe() elif model_name == MODELS['t5enro'] or model_name == MODELS['pegasus'] or model_name == MODELS['mbartenro']: translation, message = src.Translate.Translators(model_name, sl, tl, input_text).translationpipe() elif model_name == MODELS['mbart']: translation, message = src.Translate.Translators(model_name, sl, tl, input_text).mbartlarge() else: translation: str = src.Translate.gemma_direct(input_text, model_name) return {"input_text": input_text, "translation": translation, "model_name": model_name, "message": message} class Bergamot: config = bergamot.ServiceConfig(numWorkers=4) service = bergamot.Service(config) def __init__(self, input_text, sl, tl, model_name): # Keep track of installed (src, tgt) pairs self.installed_pairs = set() self.input_text, self.sl, self.tl, self.model_name = input_text, sl, tl, model_name self.repo_id = "TiberiuCristianLeon/Bergamot" self.branches = ['base', 'base-memory', 'tiny'] self.subfolder = f"{sl}{tl}" self.localfolder = f"{self.subfolder}/{model_name}" # List all files in the repo self.all_files = list_repo_files(self.repo_id, repo_type='model') def downloadbergamotfiles(self): print('input text type:', type(self.input_text), len(self.all_files), 'installed_pairs', self.installed_pairs, 'defaultlocalfolder', self.localfolder) try: for branch in self.branches: branch_files = [f for f in self.all_files if f.startswith(branch)] fullmodel_files = [f for f in branch_files if f.startswith(self.model_name)] print('branch_files', len(branch_files), 'fullmodel_files', fullmodel_files) model_files = [f.split(f'{self.model_name}/')[1] for f in fullmodel_files] print('branch_files', len(branch_files), 'model_files', model_files) for file_path in model_files: if self.localfolder not in self.installed_pairs: # local_files_only (bool, optional, defaults to False) — If True, avoid downloading the file and return the path to the local cached file if it exists. # dry_run (bool, optional, defaults to False) — If True, perform a dry run without actually downloading the file. Returns a DryRunFileInfo object containing information about what would be downloaded. local_path = hf_hub_download(repo_id=self.repo_id, subfolder=self.model_name, filename=file_path, local_dir=self.subfolder) print(f"Downloaded to: {local_path}") # Downloaded to: deen/base/deen/config.yml try: dry_run = hf_hub_download(repo_id=self.repo_id, subfolder=self.model_name, filename='config.yml', local_dir=self.subfolder) print('installed_pairs', self.installed_pairs, 'localfolder', self.localfolder, 'dry_run', type(dry_run), dry_run) if isinstance(dry_run, str): print('Add to set after dryrun', dry_run) self.installed_pairs.add(self.localfolder) except Exception as dryrunerror: print('installed_pairs', self.installed_pairs, 'localfolder', self.localfolder, 'dry_runerror', dryrunerror) except Exception as downloaderror: response, message_text = str(downloaderror), f"Error downloading {self.model_name}: {downloaderror}." print(downloaderror) def translate(self): self.downloadbergamotfiles() try: model = self.service.modelFromConfigPath(f"{self.localfolder}/config.yml") options = bergamot.ResponseOptions(alignment=False, sentenceMappings=False, qualityScores=False, HTML=False) rawresponse = self.service.translate(model, bergamot.VectorString(self.input_text), options) response: list|str = [r.target.text for r in rawresponse] if len(rawresponse) > 1 else next(iter(rawresponse)).target.text print(type(self.input_text), len(self.input_text), len(rawresponse), type(response), response) message_text = f"Translated from {self.sl} to {self.tl} with {self.model_name}." except Exception as translateerror: response, message_text = str(translateerror), f"Error translating from {self.sl} to {self.tl} with {self.model_name}: {translateerror}." print(translateerror) return {"input": self.input_text, "translated_text": response, "message_text": message_text} # https://tiberiucristianleon-fastapimt.hf.space/bergamot?input_text=das%20ist%20keine%20gute%20Frau&input_text=das%20ist%20eine%20gute%20Nachricht&sl=de&tl=en&model=bergamot @app.get("/bergamott", operation_id="get_bergamott", description="Translate text with Bergamot", tags=["bergamott"], summary="Translate text with Bergamot") def bergamott(input_text: list[str] = Query(description="Input string or list of strings"), sl: str = 'de', tl: str = 'en', model_name: Optional[str] = 'base/deen'): """ Translates the input text from the source language to the target language using a specified model. Parameters: input_text (str | list[str]): The source text to be translated, can be either a string or a list of strings sl (str): The source language of the input text tl (str): The target language into which the input text is translated model_name (str): The selected translation model name Returns: dict: input_text(str): The input text in the source language translated_text(str): The input text translated into the selected target language message_text(str): A descriptive message summarizing the translation process. Example: "Translated from English to German with base/ende." Example: >>> bergamot("Hello world", "en", "de", "base/ende") {"input_text": "Hello world", "translated_text": "Hallo Welt", "message_text": "Translated from English to German with base/ende."} """ try: bergamotinstance = Bergamot(input_text, sl, tl, model_name) return bergamotinstance.translate() except Exception as mainerror: response, message_text = str(mainerror), f"Error translating from {sl} to {tl} with {model_name}: {mainerror}." print(mainerror) # https://tiberiucristianleon-fastapimt.hf.space/bergamot?input_text=das%20ist%20keine%20gute%20Frau&input_text=das%20ist%20eine%20gute%20Nachricht&sl=de&tl=en&model=bergamot @app.get("/bergamots", operation_id="get_bergamot", description="Translate text with Bergamot", tags=["bergamots"], summary="Translate text with Bergamot") def bergamots(input_text: list[str] = Query(description="Input string or list of strings"), sl: str = 'de', tl: str = 'en', model_name: Optional[str] = 'base/deen'): """ Translates the input text from the source language to the target language using a specified model. Parameters: input_text (str | list[str]): The source text to be translated, can be either a string or a list of strings sl (str): The source language of the input text tl (str): The target language into which the input text is translated model_name (str): The selected translation model name Returns: dict: input_text(str): The input text in the source language translated_text(str): The input text translated into the selected target language message_text(str): A descriptive message summarizing the translation process. Example: "Translated from English to German with base/ende." Example: >>> bergamot("Hello world", "en", "de", "base/ende") {"input_text": "Hello world", "translated_text": "Hallo Welt", "message_text": "Translated from English to German with base/ende."} """ try: import bergamot repo_id="TiberiuCristianLeon/Bergamot" branches = ['base', 'base-memory', 'tiny'] # input_text = [input_text] if isinstance(input_text, str) else input_text config = bergamot.ServiceConfig(numWorkers=4) service = bergamot.Service(config) subfolder = f"{sl}{tl}" localfolder = f"{subfolder}/{model_name}" # List all files in the repo all_files = list_repo_files(repo_id, repo_type='model') print('input text type:', type(input_text), len(all_files), 'installed_pairs', installed_pairs, 'defaultlocalfolder', localfolder) for branch in branches: branch_files = [f for f in all_files if f.startswith(branch)] fullmodel_files = [f for f in branch_files if f.startswith(model_name)] print('branch_files', len(branch_files), 'fullmodel_files', fullmodel_files) model_files = [f.split(f'{model_name}/')[1] for f in fullmodel_files] print('branch_files', len(branch_files), 'model_files', model_files) for file_path in model_files: if localfolder not in installed_pairs: # local_files_only (bool, optional, defaults to False) — If True, avoid downloading the file and return the path to the local cached file if it exists. # dry_run (bool, optional, defaults to False) — If True, perform a dry run without actually downloading the file. Returns a DryRunFileInfo object containing information about what would be downloaded. local_path = hf_hub_download(repo_id=repo_id, subfolder=model_name, filename=file_path, local_dir=subfolder) print(f"Downloaded to: {local_path}") # Downloaded to: deen/base/deen/config.yml ## Check if model/localfolder in repo files, add to set if exists modelcheck = [i for i in all_files if model_name in i] print('Modelcheck', modelcheck) if modelcheck: print('Add to set after modelcheck', modelcheck) installed_pairs.add(localfolder) try: dry_run = hf_hub_download(repo_id=repo_id, subfolder=model_name, filename='config.yml', local_dir=subfolder) print('installed_pairs', installed_pairs, 'localfolder', localfolder, 'dry_run', type(dry_run), dry_run) if isinstance(dry_run, str): print('Add to set after dryrun', dry_run) installed_pairs.add(localfolder) except Exception as dryrunerror: print('installed_pairs', installed_pairs, 'localfolder', localfolder, 'dry_runerror', dryrunerror) model = service.modelFromConfigPath(f"{localfolder}/config.yml") # model = service.modelFromConfig(localfolder) options = bergamot.ResponseOptions(alignment=False, sentenceMappings=False, qualityScores=False, HTML=False) rawresponse = service.translate(model, bergamot.VectorString(input_text), options) response: list|str = [r.target.text for r in rawresponse] if len(rawresponse) > 1 else next(iter(rawresponse)).target.text print(type(input_text), len(input_text), len(rawresponse), type(response), response) # response = [r.target.text for r in model_response][0] if isinstance(response, bergamot._bergamot.VectorResponse) else next(iter(response)).target.text # response is of type bergamot._bergamot.VectorResponse, an iterable of bergamot._bergamot.Response message_text = f"Translated from {sl} to {tl} with {model_name}." except Exception as generalerror: response, message_text = str(generalerror), f"Error translating from {sl} to {tl} with {model_name}: {generalerror}." print(generalerror) return {"input": input_text, "translated_text": response, "message_text": message_text} @app.get("/embed", operation_id="get_embeddings", description="Embed text", tags=["embed"], summary="Embed text") def embed(text: str, model: str = EMBEDDING_MODEL): model = SentenceTransformer(model) embeddings = model.encode(text) print(embeddings.shape, len(embeddings)) # similarities = model.similarity(embeddings, embeddings) return {"input": text, "embeddings": embeddings.tolist(), "shape": embeddings.shape} # Create an MCP server based on this app mcp = FastApiMCP( app, name="Translate and paraphrase FASTAPI MCP", description="MCP server to translate and paraphrase text", describe_all_responses=True, describe_full_response_schema=True, include_operations=["get_translate", "get_paraphrase"], include_tags=["paraphrase", "translate", "bergamott"] ) # Mount the MCP server directly to the FASTAPI app mcp.mount()