I want to run a Speech Recognition app as a flask endpoint?
Below is an example of how to expose your Whisper-based speech recognition functionality as a Flask endpoint. In this example, the server accepts an audio file via a POST request, processes it with the Whisper model, and returns the transcription as JSON.
Example: app.py
python
from flask import Flask, request, jsonify
import whisper
import os
import uuid
import soundfile as sf
app = Flask(__name__)
# Load the Whisper model (choose "base", "small", "medium", or "large")
model = whisper.load_model("base")
@app.route("/transcribe", methods=["POST"])deftranscribe():
# Check if an audio file is included in the requestif"audio"notin request.files:
return jsonify({"error": "No audio file provided."}), 400
audio_file = request.files["audio"]
# Generate a unique filename to temporarily store the audio file
temp_filename = f"temp_{uuid.uuid4().hex}.wav"
audio_file.save(temp_filename)
try:
# Optional: Ensure the audio is 16kHz. # This reads the file and, if needed, rewrites it with the correct sample rate.
audio_data, samplerate = sf.read(temp_filename)
if samplerate != 16000:
sf.write(temp_filename, audio_data, 16000)
except Exception as e:
os.remove(temp_filename)
return jsonify({"error": "Failed to process audio file", "details": str(e)}), 500try:
# Run transcription using Whisper
result = model.transcribe(temp_filename)
transcription = result.get("text", "")
except Exception as e:
os.remove(temp_filename)
return jsonify({"error": "Transcription failed", "details": str(e)}), 500# Clean up the temporary file
os.remove(temp_filename)
return jsonify({"transcription": transcription})
if __name__ == "__main__":
# Run the Flask server on 0.0.0.0 so it's accessible on your network
app.run(debug=True, host="0.0.0.0", port=5000)
How to Run the Flask Endpoint on Linux/Ubuntu
Install Dependencies
Make sure you have the necessary packages installed. Open your terminal and run:
Note: The ffmpeg package is useful for handling various audio formats.
Save the Code
Save the code above into a file named app.py.
Run the Flask Server
In your terminal, navigate to the folder where app.py is saved and execute:
sh
python app.py
The server will start on port 5000 and be accessible at http://0.0.0.0:5000/transcribe.
Test the Endpoint
You can test the endpoint using tools like curl or Postman. For example, using curl:
sh
curl -X POST -F "audio=@path/to/your/audio.wav" http://localhost:5000/transcribe
You should receive a JSON response with the transcription.
Additional Considerations
Audio Preprocessing:
In a production system, you might want to include more robust audio processing (e.g., noise reduction, resampling using a dedicated library) before passing the file to the model.
Error Handling:
The code includes basic error handling for missing files and processing issues. You can extend these handlers to meet your application's needs.
Deployment:
When deploying in production, consider using a production-grade server like Gunicorn behind a reverse proxy (e.g., Nginx).
This setup transforms your offline Whisper-based speech recognition functionality into a RESTful Flask endpoint that you can call from any client.
Can you also provide a webpage to run as per this flask endpoint?
But note: I want to record user voice and send that
Below is an example HTML page that uses the browser’s MediaRecorder API to record the user’s voice, then sends the recorded audio as a file to your Flask endpoint. In this example, the endpoint is assumed to be hosted on the same origin at /transcribe. (If it’s hosted elsewhere, simply update the URL.)
Note:
Most browsers will record audio as WebM/Opus. On the Flask side, if needed, you can use ffmpeg (or similar) to convert the file to WAV or another format that works best with Whisper. Alternatively, you can modify the Flask code to accept WebM input.
The page requests microphone access via navigator.mediaDevices.getUserMedia({ audio: true }).
Recording:
A MediaRecorder instance records the audio stream.
Recorded chunks are stored in an array.
Stopping & Sending Audio:
When the user clicks the button again (now labeled Stop Recording), the recorder stops.
The recorded chunks are assembled into a Blob (with MIME type audio/webm).
The Blob is appended to a FormData object and sent via a fetch() POST request to the /transcribe endpoint.
Display Results:
The Flask endpoint processes the audio and returns a JSON object with the transcription.
The transcription is then displayed on the webpage.
This simple webpage allows you to record audio in the browser and send it to your Flask endpoint where Whisper can process it. Adjust the MIME type or perform client-side conversion if your Flask endpoint requires a specific audio format.
Tags: Technology,Generative AI,Large Language Models,
Apple emphasises AI capabilities of the Mac Studio, with the M3 Ultra model supporting large language models (LLMs) with over 600 billion parameters entirely in memory
Apple on Wednesday (March 5, 2025) announced the latest iteration of its Mac Studio, touting it as the most powerful Mac ever made. Equipped with the new M4 Max and M3 Ultra chips, the compact desktop is designed for professionals who require top-tier performance. The new Mac Studio introduces Thunderbolt 5 for faster connectivity, up to 512GB of unified memory, and 16TB of SSD storage—all within a compact and quiet design meant to sit right on a desk.
Apple claims the new Mac Studio provides massive performance gains compared to previous models, making it an ideal choice for users working with AI, video production, and other intensive tasks.
Apple emphasises AI capabilities of the Mac Studio, with the M3 Ultra model supporting large language models (LLMs) with over 600 billion parameters entirely in memory. This makes it a powerhouse for AI workloads, offering high efficiency for machine learning and creative applications. It is also optimised for Apple Intelligence, which enhances productivity and privacy. The new Mac Studio is available for pre-order today, with general availability starting March 12.
Mac Studio with M4 Max
The M4 Max version of Mac Studio is designed for video editors, developers, engineers, and creative professionals. It features a 16-core CPU, a 40-core GPU, and over 500GB/s of memory bandwidth, making it significantly faster than the M1 Max-based Mac Studio. Apple reports that the M4 Max delivers up to 3.5x the performance of the M1 Max model and is 6.1x faster than the most powerful Intel-based 27-inch iMac. With up to 128GB of unified memory, users can handle complex workflows, including large-scale image processing and high-resolution video editing.
Mac Studio with M3 Ultra
For those needing even greater power, the M3 Ultra version of the Mac Studio is the ultimate professional desktop. It boasts an up to 32-core CPU, an 80-core GPU, and 800GB/s of memory bandwidth, delivering nearly twice the performance of M4 Max in multi-threaded workloads. Apple claims that Mac Studio with M3 Ultra is 2.6x faster than its M1 Ultra predecessor and 6.4x faster than the Intel Xeon-based Mac Pro. It supports up to 512GB of unified memory, the highest ever in a personal computer, making it a game-changer for AI, video production, and 3D rendering.
Apple has upgraded the Mac Studio’s connectivity with Thunderbolt 5, offering speeds up to 120 Gb/s, three times faster than the previous generation. This allows for faster external storage, expansion chassis, and multi-display setups. The M3 Ultra model can drive up to eight Pro Display XDRs at full 6K resolution, making it ideal for professionals who require extensive screen real estate. The Mac Studio also includes a 10Gb Ethernet port, HDMI, an SDXC card slot, built-in Wi-Fi, and Bluetooth, providing a well-rounded set of connectivity options.
macOS Sequoia and Apple Intelligence
The new Mac Studio runs on macOS Sequoia, offering features like iPhone Mirroring, enhanced window management, and a redesigned Safari experience. With Apple Intelligence, users can take advantage of AI-powered writing tools, priority notifications, live transcription, and ChatGPT integration in Siri. Apple ensures that privacy remains a top priority, using on-device processing and Private Cloud Compute to handle AI tasks securely.
Mac Studio (2025) Key Specifications
Feature Mac Studio with M4 Max Mac Studio with M3 Ultra
CPU 16-core 32-core (24 performance cores)
GPU 40-core 80-core
Neural Engine 3x faster than M1 Max 32-core for AI/ML tasks
Memory Up to 128GB unified memory Up to 512GB unified memory
Feature Mac Studio with M4 Max Mac Studio with M3 Ultra
Storage Up to 16TB SSD Up to 16TB SSD
Memory Bandwidth 500GB/s+ 800GB/s+
Connectivity Thunderbolt 5, 10Gb Ethernet, HDMI, SDXC Thunderbolt 5, 10Gb Ethernet, HDMI, SDXC
AI Performance Runs LLMs efficiently Handles 600B+ parameter models in memory
Display Support Multiple 6K displays Up to 8 Pro Display XDRs at 6K resolution
Ref
Tags: Technology,Generative AI,Large Language Models,Artificial Intelligence,
A MySQL username (same as your PythonAnywhere username).
A MySQL password (auto-generated, but you can reset it).
A MySQL host (usually your_username.mysql.pythonanywhere-services.com).
🔹 Step 3: Connect to MySQL from PythonAnywhere Console
To check if the database is working, open a Bash console in PythonAnywhere and run:
bash
mysql -u your_username -h your_username.mysql.pythonanywhere-services.com -p
Enter your MySQL password when prompted.
To list databases:
sql
SHOW DATABASES;
To switch to your database:
sql
USE your_username$mydatabase;
🔹 Step 4: Connect to MySQL from a Flask App
Install mysql-connector-python (if not already installed):
bash
pip install mysql-connector-python
Then, create a Python script (app.py):
python
import mysql.connector
# Database credentials from PythonAnywhere
DB_CONFIG = {
"host": "your_username.mysql.pythonanywhere-services.com",
"user": "your_username",
"password": "your_mysql_password",
"database": "your_username$mydatabase"
}
# Connect to MySQLtry:
db = mysql.connector.connect(**DB_CONFIG)
cursor = db.cursor()
print("Connected to MySQL successfully!")
# Create a table (if needed)
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100) UNIQUE
)
""")
print("Table created!")
# Close connection
cursor.close()
db.close()
except mysql.connector.Error as err:
print(f"Error: {err}")
Run the script:
bash
python app.py
🔹 Step 5: Access MySQL from PythonAnywhere Web App
If you're deploying a Flask app on PythonAnywhere:
Go to "Web" and create a new Flask app.
Make sure app.py uses the correct MySQL hostname (not localhost but your_username.mysql.pythonanywhere-services.com).
Restart the web app after changes.
✅ Final Checklist
✔ Use your full database name (your_username$mydatabase). ✔ Use PythonAnywhere’s MySQL hostname (your_username.mysql.pythonanywhere-services.com). ✔ Avoid using localhost in your connection string.
Let me know if you need further help! 🚀
Testing the MySQL Database
mysql> use ashishjaindrive1$default
Database changed
mysql>
mysql> create table users (name varchar(100));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into users values('ram');
Query OK, 1 row affected (0.01 sec)
mysql> insert into users values('ravan');
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql>
How to install python-dotenv?
12:23 ~/mysite $ pip install python-dotenv
Defaulting to user installation because normal site-packages is not writeable
Looking in links: /usr/share/pip-wheels
Collecting python-dotenv
Downloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)
Installing collected packages: python-dotenv
Successfully installed python-dotenv-1.0.1
12:25 ~/mysite $
from langchain_google_genai import ChatGoogleGenerativeAI
import json
with open('../api_keys.json', mode = 'r') as f:
api_keys = json.load(f)
# Initialize the client with your API key
llm = ChatGoogleGenerativeAI(
model="gemini-2.0-flash",
google_api_key=api_keys['ashishjain1547']
)
from langgraph.graph import StateGraph, END
from langchain_community.document_loaders import WebBaseLoader
from langchain.chat_models import ChatOpenAI
import os
from typing import TypedDict, Annotated
class AgentState(TypedDict):
nlq: str
metadata: dict
refined_query: str
further_refined_query: str
feedback: str
itr_count: int
import re
def extract_triple_quoted_json(response_text):
# This pattern looks for a JSON object (starting with '{' and ending with '}')
# enclosed in either triple double-quotes or triple single-quotes.
pattern = r'(?:\'\'\'|""")\s*(\{.*?\})\s*(?:\'\'\'|""")'
match = re.search(pattern, response_text, re.DOTALL)
if match:
return match.group(1)
return None
class ReEngineerQuery:
def __init__(self, model):
self.model = model
graph = StateGraph(AgentState)
graph.add_node("refine_query", self.refine_query)
graph.add_node("evaluate_reengineered_query", self.evaluate_reengineered_query)
graph.add_node("further_refine_query", self.further_refine_query)
# --- Edges ---
graph.set_entry_point("refine_query")
graph.add_edge("refine_query", "evaluate_reengineered_query")
graph.add_edge("evaluate_reengineered_query", "further_refine_query")
graph.add_conditional_edges(
"further_refine_query",
self.should_continue,
{"end": END, "refine_query": "refine_query"}
)
# Compile the graph and store references
self.graph = graph.compile()
def refine_query(self, state):
META_PROMPT_TO_REENGINEER_NLQ = """
You are an expert SQLite query generator. Based on the natural language query and the provided table metadata,
please reengineer the query to clearly specify:
- The specific table(s) that should be referenced,
- The calculations or aggregations to perform,
- The structure of the final SQL query.
NLQ: {nlq}
Table Metadata:
{metadata}
Reengineered Query:
"""
# Build the meta-prompt by substituting the NLQ and metadata.
prompt = META_PROMPT_TO_REENGINEER_NLQ.format(nlq=state.get("nlq", ""), metadata=state.get("metadata", ""))
# Invoke the LLM with the prompt.
response = self.model(prompt)
# Return the refined query.
return {"refined_query": response.strip(), "itr_count": state.get("itr_count") + 1}
def evaluate_reengineered_query(self, state):
EVALUATE_REENGINEERED_QUERY = """
You are an expert SQLite engineer grading an NLQ for correctness, completeness and clarity. \
Generate critique and recommendations for the NLQ so it can be easily converted to an SQL. \
Please evaluate the reengineered query below:
{refined_query}
"""
prompt = EVALUATE_REENGINEERED_QUERY.format(refined_query=state.get("refined_query", ""))
response = self.model(prompt)
return {"feedback": response.strip()}
def further_refine_query(self, state):
REENGINEER_QUERY_POST_FEEDBACK = """
You are an expert SQLite query generator. Based on the natural language query, the provided table metadata and feedback,
please reengineer the query based on the feedback given to clearly specify:
- The specific table(s) that should be referenced,
- The calculations or aggregations to perform,
- The structure of the final SQL query.
NLQ: {nlq}
Table Metadata:
{metadata}
Feedback:
{feedback}
Reengineered Query:
""" # Build the meta-prompt by substituting the NLQ and metadata.
prompt = REENGINEER_QUERY_POST_FEEDBACK.format(nlq=state.get("nlq", ""), metadata=state.get("metadata", ""),
feedback=state.get("feedback", ""))
# Invoke the LLM with the prompt.
response = self.model(prompt)
print(response)
return {"further_refined_query": response.strip(), "itr_count": state.get("itr_count") + 1}
def should_continue(self, state):
CHECK_CONSISTENCY = """
You are an expert database query evaluator. Your task is to evaluate two queries \
if they are consistent and mean the same thing. One query is the last query and the other is the reengineered query. \
Last Query: {refined_query}
Reengineered Query: {further_refined_query}
Is the reengineered query consistent with the last query?
Return a JSON response with the key 'answer': 'yes' or 'no'."""
prompt = CHECK_CONSISTENCY.format(refined_query=state.get("refined_query", ""), further_refined_query=state.get("further_refined_query", ""))
response = self.model(prompt)
#extract json from the response
print(response)
json_response = "{" + response.split("{")[1].split("}")[0].strip().replace("'", '"') + "}"
json_response = json.loads(json_response)
print(json_response)
if json_response['answer'] == "yes":
return "end"
return "refine_query"
class MyGeminiChatModel:
"""
Minimal wrapper that expects a prompt and returns GPT-3.5 Turbo response text.
"""
def __init__(self, api_key):
self.client = ChatGoogleGenerativeAI(
model="gemini-2.0-flash",
google_api_key = api_key
)
def bind_tools(self, tools):
return self # For compatibility with how TranslatorCriticApp uses .bind_tools
def __call__(self, prompt: str) -> str:
response = llm.invoke(prompt)
return response.content
model = MyGeminiChatModel(api_keys["ashishjain1547"])
app = ReEngineerQuery(model)
from IPython.display import Image
Image(app.graph.get_graph().draw_png())
<IMG>
with open('tables.json', mode = 'r') as f:
metadata = json.load(f)
nlq = "Show me the orders from last year."
refined_query = ""
further_refined_query = ""
feedback = ""
itr_count = 0
result = app.graph.invoke({"nlq": nlq, "metadata": metadata, "refined_query": refined_query, "further_refined_query": further_refined_query, "feedback": feedback, "itr_count": itr_count})
SELECT * FROM AB_ORDERS WHERE ORDERYEAR = CAST(STRFTIME('%Y', DATE('now', '-1 year')) AS INTEGER)nlq = "Show all tables"
refined_query = ""
further_refined_query = ""
feedback = ""
itr_count = 0
result = app.graph.invoke({"nlq": nlq, "metadata": metadata, "refined_query": refined_query, "further_refined_query": further_refined_query, "feedback": feedback, "itr_count": itr_count})To show all tables in the SQLite database, you can use the following SQL query:
```sql
SELECT name
FROM sqlite_master
WHERE type='table';
```
This query retrieves the names of all tables present in the SQLite database by querying the `sqlite_master` table where the `type` column is equal to 'table'. Knowing all the tables in the database is essential for database management, schema understanding, and querying purposes. It helps in identifying the available data structures, relationships between tables, and overall database organization. This information is crucial for developers, analysts, and administrators to effectively work with the database and perform various operations such as data retrieval, manipulation, and optimization.nlq = "What's in orders table?"
refined_query = ""
further_refined_query = ""
feedback = ""
itr_count = 0
result = app.graph.invoke({"nlq": nlq, "metadata": metadata, "refined_query": refined_query, "further_refined_query": further_refined_query, "feedback": feedback, "itr_count": itr_count})SELECT * FROM AB_ORDERSnlq = "Show me top 5 categories with respect to orders."
refined_query = ""
further_refined_query = ""
feedback = ""
itr_count = 0
result = app.graph.invoke({"nlq": nlq, "metadata": metadata, "refined_query": refined_query, "further_refined_query": further_refined_query, "feedback": feedback, "itr_count": itr_count})SELECT C.CATEGORYNAME, COUNT(O.ORDERID) AS ORDER_COUNT
FROM AB_CATEGORIES C
JOIN AB_PRODUCTS P ON C.CATEGORYID = P.CATEGORYID
JOIN AB_ORDERDETAILS OD ON P.PRODUCTID = OD.PRODUCTID
JOIN AB_ORDERS O ON OD.ORDERID = O.ORDERID
GROUP BY C.CATEGORYNAME
ORDER BY ORDER_COUNT DESC
LIMIT 5;nlq = "Which areas are dairy products sold?"
refined_query = ""
further_refined_query = ""
feedback = ""
itr_count = 0
result = app.graph.invoke({"nlq": nlq, "metadata": metadata, "refined_query": refined_query, "further_refined_query": further_refined_query, "feedback": feedback, "itr_count": itr_count})SELECT DISTINCT C.CITY AS AREA
FROM AB_CUSTOMERS C
JOIN AB_ORDERS O ON C.CUSTOMERID = O.CUSTOMERID
JOIN AB_ORDERDETAILS OD ON O.ORDERID = OD.ORDERID
JOIN AB_PRODUCTS P ON OD.PRODUCTID = P.PRODUCTID
JOIN AB_CATEGORIES CAT ON P.CATEGORYID = CAT.CATEGORYID
WHERE CAT.CATEGORYNAME = 'Dairy Products';nlq = "Compare orders from top two cities with respect to total sales."
refined_query = ""
further_refined_query = ""
feedback = ""
itr_count = 0
result = app.graph.invoke({"nlq": nlq, "metadata": metadata, "refined_query": refined_query, "further_refined_query": further_refined_query, "feedback": feedback, "itr_count": itr_count})-- Query to compare total sales from the top two cities
SELECT
c.CITY AS City,
SUM(p.PRICE * od.QUANTITY) AS TotalSales
FROM
AB_CUSTOMERS c
JOIN
AB_ORDERS o ON c.CUSTOMERID = o.CUSTOMERID
JOIN
AB_ORDERDETAILS od ON o.ORDERID = od.ORDERID
JOIN
AB_PRODUCTS p ON od.PRODUCTID = p.PRODUCTID
GROUP BY
c.CITY
ORDER BY
TotalSales DESC
LIMIT 2;
The average bench time at present has come down to 35-45 days compared to an average of 45-60 days in FY20 and FY21, when the sector’s revenue growth for the sector was in the higher double digits.
Top Indian IT services companies, including Tata Consultancy Services (TCS), Infosys, Wipro, HCLTech, and Accenture, among others, have been reducing bench sizes in the past year and a half in a bid to defend margins and improve utilisation rates as revenue growth remains slow.
Staffing firms and industry experts said that not just bench sizes, even the bench holding timelines have plunged significantly. Benching in IT services industry refers to the employees on payroll who haven’t been deployed on any active projects. They are usually kept as a backup in case of a sudden client demand arises.
According to data sourced from market intelligence firm UnearthInsight, the average bench time at present has come down to 35-45 days compared to an average of 45-60 days in FY20 and FY21, when the sector’s revenue growth was in the higher double digits. This trend is expected to continue in FY26 too.
Currently, employees with nine to 14 years of experience across legacy skills too are at the risk of bench layoffs, as niche skills related to artificial intelligence, machine learning and cloud are more in demand.
Meanwhile, benched employees which accounted for 10-15% of the average overall headcount mix of the IT companies have now come down to just 2-5%, according to data from staffing firm TeamLease Digital.
Kamal Karanth, co-founder of specialised staffing firm, Xpheno explained that the high bench volumes in calendar year 2022 and early 2023 were an outcome of the hyper-hiring in 2021 and early 2022, resulting in lower utilization rates.
“The resizing and rebalancing of headcounts since 2023, amidst revenue and margin pressures hit the bench volumes first to move the utilisation rates up again. Enterprises have since gone for a mix of staffing consumption for just-in-time workforce and subcon arrangements for longer tenures,” he told Moneycontrol.
Krishna Vij, business head-IT staffing at TeamLease Digital said, “From 70-75% utilisation, companies have started reaching 80-85% utilisation rates. The attrition has also reduced to 11-13% from 28-30%, When you are not losing people you will not be utilising the benched resources. With GCCs hiring directly from the talent pool, IT firms have started facing increased competition. So they started opting for leaner and project specific hiring models.
While current utilisation rates stayed in the optimal mid to late 80 percent range for IT firms, estimated bench sizes have shrunk by 15 percent compared to the size a year ago. On a 2-year basis, the estimated bench size reduction is nearly 22 percent, data from Xpheno said.
Select Tier-I firms such as TCS do maintain a slightly higher lateral bench to respond to clients for faster or immediate deployment. However, in times of slow down when deal closures are getting delayed, IT services firms have to optimise costs, according to Gaurav Vasu, founder and CEO, UnearthInsight.
He added, “Around 2-3 months is the current bench policy for laterals but Tier I firms like TCS, Infosys, Wipro, HCL, Accenture are looking at faster deployment to projects from bench hence bench optimization is a normal activity specially for skills not in demand or skills where demand visibility is weak.”
This reflected in the negative quarterly headcount addition of most of the top five Indian IT companies, even as overall the sector has started hiring more as compared to the previous fiscal seeing some green shoots in demand environment.
IT companies on the other hand have started highlighting a fundamental shift in traditional tech services business models and the need to overhaul it, as AI has started driving productivity gains for customers bringing down project tenures and sizes.
Last week, HCLTech CEO and MD C Vijayakumar said, “The business model is ripe for disruption, what we saw in the last 30 years a fairly linear scalling of IT service. I think the time is already out for that model and in the last couple of years we have been challenging our teams on how you can deliver twice the revenue with half the people, that’s really what I found I make through a lot of my teams.”
He was speaking at the Nasscom Technology and Leadership Forum (NTLF) 2025 in Mumbai.
Distribution of talent
Not just demand cycles and AI disruption, the bench layoff trends are also an implication of the location of the delivery centres, said Vasu.
He shared that managing a bench in smaller cities both globally and in India has been difficult as niche skills-focused projects don’t see many takers for the tier II cities often. “IT companies try to take fungible skills or vanilla skills to Tier-II cities, global low cost cities as both time and cost of bench could directly impact EBIT negatively. Currently 0% to 0.25% of the headcount of a Tier-II city based campus or delivery centre will be on bench across vanilla (legacy skills) and niche skills,” he said.
Another staffing firm business lead seeking anonymity said that certain IT majors especially Tier-I firms don’t want to keep any bench. They are even passing the bench pressure to staffing firms.
“They don’t have to invest on the bench, but staffing firms have to bear the costs to retain the engagement with the client IT firm. Depending on how the projects come, staffing firms will then deploy the candidates. Until then, the benched candidates will be on staffing firms’ payrolls. That’s one way of doing it,” the person said.
Ref