vbuenosa-nttd commited on
Commit
36ebfb6
·
verified ·
1 Parent(s): 0617a07

Deploying TechHub Prototype

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .dockerignore +7 -0
  2. .gitattributes +50 -0
  3. Dockerfile +33 -0
  4. referenceDocs/Get_started_LiveAPI.py +275 -0
  5. techhubprototypeucbackend/.env +1 -0
  6. techhubprototypeucbackend/.env.example +5 -0
  7. techhubprototypeucbackend/.pytest_cache/.gitignore +2 -0
  8. techhubprototypeucbackend/.pytest_cache/CACHEDIR.TAG +4 -0
  9. techhubprototypeucbackend/.pytest_cache/README.md +8 -0
  10. techhubprototypeucbackend/.pytest_cache/v/cache/lastfailed +1 -0
  11. techhubprototypeucbackend/.pytest_cache/v/cache/nodeids +4 -0
  12. techhubprototypeucbackend/__pycache__/main.cpython-312.pyc +0 -0
  13. techhubprototypeucbackend/main.py +190 -0
  14. techhubprototypeucbackend/requirements.txt +12 -0
  15. techhubprototypeucbackend/tests/__pycache__/test_main.cpython-312-pytest-8.4.2.pyc +0 -0
  16. techhubprototypeucbackend/tests/test_main.py +46 -0
  17. techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/INSTALLER +1 -0
  18. techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/LICENSE.txt +20 -0
  19. techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/METADATA +72 -0
  20. techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/RECORD +10 -0
  21. techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/REQUESTED +0 -0
  22. techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/WHEEL +5 -0
  23. techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/top_level.txt +1 -0
  24. techhubprototypeucbackend/venv/Lib/site-packages/__pycache__/py.cpython-312.pyc +0 -0
  25. techhubprototypeucbackend/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc +3 -0
  26. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__init__.py +13 -0
  27. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/__init__.cpython-312.pyc +0 -0
  28. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/_argcomplete.cpython-312.pyc +0 -0
  29. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/_version.cpython-312.pyc +0 -0
  30. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/cacheprovider.cpython-312.pyc +0 -0
  31. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/capture.cpython-312.pyc +0 -0
  32. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/compat.cpython-312.pyc +0 -0
  33. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/debugging.cpython-312.pyc +0 -0
  34. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/deprecated.cpython-312.pyc +0 -0
  35. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/doctest.cpython-312.pyc +0 -0
  36. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/faulthandler.cpython-312.pyc +0 -0
  37. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/fixtures.cpython-312.pyc +0 -0
  38. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/freeze_support.cpython-312.pyc +0 -0
  39. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/helpconfig.cpython-312.pyc +0 -0
  40. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/hookspec.cpython-312.pyc +0 -0
  41. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/junitxml.cpython-312.pyc +0 -0
  42. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/legacypath.cpython-312.pyc +0 -0
  43. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/logging.cpython-312.pyc +0 -0
  44. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/main.cpython-312.pyc +0 -0
  45. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/monkeypatch.cpython-312.pyc +0 -0
  46. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/nodes.cpython-312.pyc +0 -0
  47. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/outcomes.cpython-312.pyc +0 -0
  48. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/pastebin.cpython-312.pyc +0 -0
  49. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/pathlib.cpython-312.pyc +0 -0
  50. techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/pytester.cpython-312.pyc +0 -0
.dockerignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ .git
2
+ .env
3
+ __pycache__
4
+ node_modules
5
+ dist
6
+ venv
7
+ *.md
.gitattributes CHANGED
@@ -33,3 +33,53 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ techhubprototypeucbackend/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
37
+ techhubprototypeucbackend/venv/Lib/site-packages/anyio/_backends/__pycache__/_asyncio.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
38
+ techhubprototypeucbackend/venv/Lib/site-packages/charset_normalizer/md__mypyc.cp312-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
39
+ techhubprototypeucbackend/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
40
+ techhubprototypeucbackend/venv/Lib/site-packages/google/_upb/_message.pyd filter=lfs diff=lfs merge=lfs -text
41
+ techhubprototypeucbackend/venv/Lib/site-packages/google/genai/__pycache__/models.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
42
+ techhubprototypeucbackend/venv/Lib/site-packages/google/genai/__pycache__/types.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
43
+ techhubprototypeucbackend/venv/Lib/site-packages/google/protobuf/__pycache__/descriptor_pb2.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
44
+ techhubprototypeucbackend/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
45
+ techhubprototypeucbackend/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
46
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
47
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe filter=lfs diff=lfs merge=lfs -text
48
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/distlib/t64.exe filter=lfs diff=lfs merge=lfs -text
49
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe filter=lfs diff=lfs merge=lfs -text
50
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/distlib/w64.exe filter=lfs diff=lfs merge=lfs -text
51
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
52
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
53
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
54
+ techhubprototypeucbackend/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
55
+ techhubprototypeucbackend/venv/Lib/site-packages/pyasn1/type/__pycache__/univ.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
56
+ techhubprototypeucbackend/venv/Lib/site-packages/pyaudio/_portaudio.cp312-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
57
+ techhubprototypeucbackend/venv/Lib/site-packages/pydantic/__pycache__/json_schema.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
58
+ techhubprototypeucbackend/venv/Lib/site-packages/pydantic/_internal/__pycache__/_generate_schema.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
59
+ techhubprototypeucbackend/venv/Lib/site-packages/pydantic_core/__pycache__/core_schema.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
60
+ techhubprototypeucbackend/venv/Lib/site-packages/pydantic_core/_pydantic_core.cp312-win_amd64.pyd filter=lfs diff=lfs merge=lfs -text
61
+ techhubprototypeucbackend/venv/Lib/site-packages/pydantic_settings/__pycache__/sources.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
62
+ techhubprototypeucbackend/venv/Lib/site-packages/pygments/lexers/__pycache__/lisp.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
63
+ techhubprototypeucbackend/venv/Scripts/dotenv.exe filter=lfs diff=lfs merge=lfs -text
64
+ techhubprototypeucbackend/venv/Scripts/fastapi.exe filter=lfs diff=lfs merge=lfs -text
65
+ techhubprototypeucbackend/venv/Scripts/httpx.exe filter=lfs diff=lfs merge=lfs -text
66
+ techhubprototypeucbackend/venv/Scripts/normalizer.exe filter=lfs diff=lfs merge=lfs -text
67
+ techhubprototypeucbackend/venv/Scripts/pip.exe filter=lfs diff=lfs merge=lfs -text
68
+ techhubprototypeucbackend/venv/Scripts/pip3.12.exe filter=lfs diff=lfs merge=lfs -text
69
+ techhubprototypeucbackend/venv/Scripts/pip3.exe filter=lfs diff=lfs merge=lfs -text
70
+ techhubprototypeucbackend/venv/Scripts/py.test.exe filter=lfs diff=lfs merge=lfs -text
71
+ techhubprototypeucbackend/venv/Scripts/pygmentize.exe filter=lfs diff=lfs merge=lfs -text
72
+ techhubprototypeucbackend/venv/Scripts/pyrsa-decrypt.exe filter=lfs diff=lfs merge=lfs -text
73
+ techhubprototypeucbackend/venv/Scripts/pyrsa-encrypt.exe filter=lfs diff=lfs merge=lfs -text
74
+ techhubprototypeucbackend/venv/Scripts/pyrsa-keygen.exe filter=lfs diff=lfs merge=lfs -text
75
+ techhubprototypeucbackend/venv/Scripts/pyrsa-priv2pub.exe filter=lfs diff=lfs merge=lfs -text
76
+ techhubprototypeucbackend/venv/Scripts/pyrsa-sign.exe filter=lfs diff=lfs merge=lfs -text
77
+ techhubprototypeucbackend/venv/Scripts/pyrsa-verify.exe filter=lfs diff=lfs merge=lfs -text
78
+ techhubprototypeucbackend/venv/Scripts/pytest.exe filter=lfs diff=lfs merge=lfs -text
79
+ techhubprototypeucbackend/venv/Scripts/python.exe filter=lfs diff=lfs merge=lfs -text
80
+ techhubprototypeucbackend/venv/Scripts/pythonw.exe filter=lfs diff=lfs merge=lfs -text
81
+ techhubprototypeucbackend/venv/Scripts/uvicorn.exe filter=lfs diff=lfs merge=lfs -text
82
+ techhubprototypeucbackend/venv/Scripts/websockets.exe filter=lfs diff=lfs merge=lfs -text
83
+ techhubprototypeucfrontend/node_modules/@esbuild/win32-x64/esbuild.exe filter=lfs diff=lfs merge=lfs -text
84
+ techhubprototypeucfrontend/node_modules/@rollup/rollup-win32-x64-gnu/rollup.win32-x64-gnu.node filter=lfs diff=lfs merge=lfs -text
85
+ techhubprototypeucfrontend/node_modules/@rollup/rollup-win32-x64-msvc/rollup.win32-x64-msvc.node filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stage 1: Build Frontend
2
+ FROM node:20 as frontend-builder
3
+
4
+ WORKDIR /app/frontend
5
+ COPY techhubprototypeucfrontend/package*.json ./
6
+ RUN npm install
7
+ COPY techhubprototypeucfrontend/ .
8
+ RUN npm run build
9
+
10
+ # Stage 2: Backend
11
+ FROM python:3.11-slim
12
+
13
+ WORKDIR /app
14
+
15
+ # Install system dependencies if needed
16
+ # RUN apt-get update && apt-get install -y --no-install-recommends gcc && rm -rf /var/lib/apt/lists/*
17
+
18
+ COPY techhubprototypeucbackend/requirements.txt .
19
+ # Remove pyaudio from requirements if it's there, as it requires system dependencies and we removed usage
20
+ RUN sed -i '/pyaudio/d' requirements.txt
21
+
22
+ RUN pip install --no-cache-dir -r requirements.txt
23
+
24
+ COPY techhubprototypeucbackend/ .
25
+
26
+ # Copy frontend build to static folder
27
+ COPY --from=frontend-builder /app/frontend/dist ./static
28
+
29
+ # Expose port 7860 (Hugging Face Spaces default)
30
+ EXPOSE 7860
31
+
32
+ # Run the app
33
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
referenceDocs/Get_started_LiveAPI.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright 2025 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """
17
+ ## Setup
18
+
19
+ To install the dependencies for this script, run:
20
+
21
+ ```
22
+ pip install google-genai opencv-python pyaudio pillow mss
23
+ ```
24
+
25
+ Before running this script, ensure the `GOOGLE_API_KEY` environment
26
+ variable is set to the api-key you obtained from Google AI Studio.
27
+
28
+ Important: **Use headphones**. This script uses the system default audio
29
+ input and output, which often won't include echo cancellation. So to prevent
30
+ the model from interrupting itself it is important that you use headphones.
31
+
32
+ ## Run
33
+
34
+ To run the script:
35
+
36
+ ```
37
+ python Get_started_LiveAPI.py
38
+ ```
39
+
40
+ The script takes a video-mode flag `--mode`, this can be "camera", "screen", or "none".
41
+ The default is "camera". To share your screen run:
42
+
43
+ ```
44
+ python Get_started_LiveAPI.py --mode screen
45
+ ```
46
+ """
47
+
48
+ import asyncio
49
+ import base64
50
+ import io
51
+ import os
52
+ import sys
53
+ import traceback
54
+
55
+ import cv2
56
+ import pyaudio
57
+ import PIL.Image
58
+ import mss
59
+
60
+ import argparse
61
+
62
+ from google import genai
63
+
64
+ if sys.version_info < (3, 11, 0):
65
+ import taskgroup, exceptiongroup
66
+
67
+ asyncio.TaskGroup = taskgroup.TaskGroup
68
+ asyncio.ExceptionGroup = exceptiongroup.ExceptionGroup
69
+
70
+ FORMAT = pyaudio.paInt16
71
+ CHANNELS = 1
72
+ SEND_SAMPLE_RATE = 16000
73
+ RECEIVE_SAMPLE_RATE = 24000
74
+ CHUNK_SIZE = 1024
75
+
76
+ MODEL = "models/gemini-2.0-flash-live-001"
77
+
78
+ DEFAULT_MODE = "camera"
79
+
80
+ client = genai.Client(http_options={"api_version": "v1beta"})
81
+
82
+ CONFIG = {"response_modalities": ["AUDIO"]}
83
+
84
+ pya = pyaudio.PyAudio()
85
+
86
+
87
+ class AudioLoop:
88
+ def __init__(self, video_mode=DEFAULT_MODE):
89
+ self.video_mode = video_mode
90
+
91
+ self.audio_in_queue = None
92
+ self.out_queue = None
93
+
94
+ self.session = None
95
+
96
+ self.send_text_task = None
97
+ self.receive_audio_task = None
98
+ self.play_audio_task = None
99
+
100
+ async def send_text(self):
101
+ while True:
102
+ text = await asyncio.to_thread(
103
+ input,
104
+ "message > ",
105
+ )
106
+ if text.lower() == "q":
107
+ break
108
+ await self.session.send(input=text or ".", end_of_turn=True)
109
+
110
+ def _get_frame(self, cap):
111
+ # Read the frameq
112
+ ret, frame = cap.read()
113
+ # Check if the frame was read successfully
114
+ if not ret:
115
+ return None
116
+ # Fix: Convert BGR to RGB color space
117
+ # OpenCV captures in BGR but PIL expects RGB format
118
+ # This prevents the blue tint in the video feed
119
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
120
+ img = PIL.Image.fromarray(frame_rgb) # Now using RGB frame
121
+ img.thumbnail([1024, 1024])
122
+
123
+ image_io = io.BytesIO()
124
+ img.save(image_io, format="jpeg")
125
+ image_io.seek(0)
126
+
127
+ mime_type = "image/jpeg"
128
+ image_bytes = image_io.read()
129
+ return {"mime_type": mime_type, "data": base64.b64encode(image_bytes).decode()}
130
+
131
+ async def get_frames(self):
132
+ # This takes about a second, and will block the whole program
133
+ # causing the audio pipeline to overflow if you don't to_thread it.
134
+ cap = await asyncio.to_thread(
135
+ cv2.VideoCapture, 0
136
+ ) # 0 represents the default camera
137
+
138
+ while True:
139
+ frame = await asyncio.to_thread(self._get_frame, cap)
140
+ if frame is None:
141
+ break
142
+
143
+ await asyncio.sleep(1.0)
144
+
145
+ await self.out_queue.put(frame)
146
+
147
+ # Release the VideoCapture object
148
+ cap.release()
149
+
150
+ def _get_screen(self):
151
+ sct = mss.mss()
152
+ monitor = sct.monitors[0]
153
+
154
+ i = sct.grab(monitor)
155
+
156
+ mime_type = "image/jpeg"
157
+ image_bytes = mss.tools.to_png(i.rgb, i.size)
158
+ img = PIL.Image.open(io.BytesIO(image_bytes))
159
+
160
+ image_io = io.BytesIO()
161
+ img.save(image_io, format="jpeg")
162
+ image_io.seek(0)
163
+
164
+ image_bytes = image_io.read()
165
+ return {"mime_type": mime_type, "data": base64.b64encode(image_bytes).decode()}
166
+
167
+ async def get_screen(self):
168
+
169
+ while True:
170
+ frame = await asyncio.to_thread(self._get_screen)
171
+ if frame is None:
172
+ break
173
+
174
+ await asyncio.sleep(1.0)
175
+
176
+ await self.out_queue.put(frame)
177
+
178
+ async def send_realtime(self):
179
+ while True:
180
+ msg = await self.out_queue.get()
181
+ await self.session.send(input=msg)
182
+
183
+ async def listen_audio(self):
184
+ mic_info = pya.get_default_input_device_info()
185
+ self.audio_stream = await asyncio.to_thread(
186
+ pya.open,
187
+ format=FORMAT,
188
+ channels=CHANNELS,
189
+ rate=SEND_SAMPLE_RATE,
190
+ input=True,
191
+ input_device_index=mic_info["index"],
192
+ frames_per_buffer=CHUNK_SIZE,
193
+ )
194
+ if __debug__:
195
+ kwargs = {"exception_on_overflow": False}
196
+ else:
197
+ kwargs = {}
198
+ while True:
199
+ data = await asyncio.to_thread(self.audio_stream.read, CHUNK_SIZE, **kwargs)
200
+ await self.out_queue.put({"data": data, "mime_type": "audio/pcm"})
201
+
202
+ async def receive_audio(self):
203
+ "Background task to reads from the websocket and write pcm chunks to the output queue"
204
+ while True:
205
+ turn = self.session.receive()
206
+ async for response in turn:
207
+ if data := response.data:
208
+ self.audio_in_queue.put_nowait(data)
209
+ continue
210
+ if text := response.text:
211
+ print(text, end="")
212
+
213
+ # If you interrupt the model, it sends a turn_complete.
214
+ # For interruptions to work, we need to stop playback.
215
+ # So empty out the audio queue because it may have loaded
216
+ # much more audio than has played yet.
217
+ while not self.audio_in_queue.empty():
218
+ self.audio_in_queue.get_nowait()
219
+
220
+ async def play_audio(self):
221
+ stream = await asyncio.to_thread(
222
+ pya.open,
223
+ format=FORMAT,
224
+ channels=CHANNELS,
225
+ rate=RECEIVE_SAMPLE_RATE,
226
+ output=True,
227
+ )
228
+ while True:
229
+ bytestream = await self.audio_in_queue.get()
230
+ await asyncio.to_thread(stream.write, bytestream)
231
+
232
+ async def run(self):
233
+ try:
234
+ async with (
235
+ client.aio.live.connect(model=MODEL, config=CONFIG) as session,
236
+ asyncio.TaskGroup() as tg,
237
+ ):
238
+ self.session = session
239
+
240
+ self.audio_in_queue = asyncio.Queue()
241
+ self.out_queue = asyncio.Queue(maxsize=5)
242
+
243
+ send_text_task = tg.create_task(self.send_text())
244
+ tg.create_task(self.send_realtime())
245
+ tg.create_task(self.listen_audio())
246
+ if self.video_mode == "camera":
247
+ tg.create_task(self.get_frames())
248
+ elif self.video_mode == "screen":
249
+ tg.create_task(self.get_screen())
250
+
251
+ tg.create_task(self.receive_audio())
252
+ tg.create_task(self.play_audio())
253
+
254
+ await send_text_task
255
+ raise asyncio.CancelledError("User requested exit")
256
+
257
+ except asyncio.CancelledError:
258
+ pass
259
+ except ExceptionGroup as EG:
260
+ self.audio_stream.close()
261
+ traceback.print_exception(EG)
262
+
263
+
264
+ if __name__ == "__main__":
265
+ parser = argparse.ArgumentParser()
266
+ parser.add_argument(
267
+ "--mode",
268
+ type=str,
269
+ default=DEFAULT_MODE,
270
+ help="pixels to stream from",
271
+ choices=["camera", "screen", "none"],
272
+ )
273
+ args = parser.parse_args()
274
+ main = AudioLoop(video_mode=args.mode)
275
+ asyncio.run(main.run())
techhubprototypeucbackend/.env ADDED
@@ -0,0 +1 @@
 
 
1
+ GOOGLE_API_KEY="AIzaSyCdGSqk7pc3yPuftVsP1EKzh4VUeQddya4"
techhubprototypeucbackend/.env.example ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Google Generative AI API Key
2
+ GOOGLE_API_KEY="YOUR_API_KEY_HERE"
3
+
4
+ # Gemini Model to use
5
+ GEMINI_MODEL="models/gemini-2.0-flash-live-001"
techhubprototypeucbackend/.pytest_cache/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Created by pytest automatically.
2
+ *
techhubprototypeucbackend/.pytest_cache/CACHEDIR.TAG ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Signature: 8a477f597d28d172789f06886806bc55
2
+ # This file is a cache directory tag created by pytest.
3
+ # For information about cache directory tags, see:
4
+ # https://bford.info/cachedir/spec.html
techhubprototypeucbackend/.pytest_cache/README.md ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # pytest cache directory #
2
+
3
+ This directory contains data from the pytest's cache plugin,
4
+ which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
5
+
6
+ **Do not** commit this to version control.
7
+
8
+ See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.
techhubprototypeucbackend/.pytest_cache/v/cache/lastfailed ADDED
@@ -0,0 +1 @@
 
 
1
+ {}
techhubprototypeucbackend/.pytest_cache/v/cache/nodeids ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ [
2
+ "tests/test_main.py::test_read_main",
3
+ "tests/test_main.py::test_websocket_connection"
4
+ ]
techhubprototypeucbackend/__pycache__/main.cpython-312.pyc ADDED
Binary file (10.5 kB). View file
 
techhubprototypeucbackend/main.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import logging
3
+ import os
4
+ import sys
5
+ import traceback
6
+
7
+ from dotenv import load_dotenv
8
+ from fastapi import FastAPI, WebSocket, WebSocketDisconnect
9
+ from fastapi.staticfiles import StaticFiles
10
+ from fastapi.responses import FileResponse
11
+ from google import genai
12
+ from google.api_core import exceptions as google_exceptions
13
+
14
+ # Configure logging
15
+ logging.basicConfig(level=logging.INFO)
16
+ logger = logging.getLogger(__name__)
17
+
18
+ load_dotenv()
19
+
20
+ if sys.version_info < (3, 11, 0):
21
+ import taskgroup, exceptiongroup
22
+
23
+ asyncio.TaskGroup = taskgroup.TaskGroup
24
+ asyncio.ExceptionGroup = exceptiongroup.ExceptionGroup
25
+
26
+ # Audio settings
27
+ # FORMAT = pyaudio.paInt16 # Removed pyaudio dependency
28
+ # CHANNELS = 1
29
+ # SEND_SAMPLE_RATE = 16000
30
+ # RECEIVE_SAMPLE_RATE = 24000
31
+ # CHUNK_SIZE = 1024
32
+
33
+ # Load configuration from environment variables
34
+ GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
35
+ MODEL = os.environ.get("GEMINI_MODEL", "models/gemini-2.0-flash-live-001")
36
+
37
+ # Configure the client with the API key
38
+ try:
39
+ if not GOOGLE_API_KEY or GOOGLE_API_KEY == "YOUR_API_KEY_HERE":
40
+ # In HF Spaces, we might set this via secrets, so we warn but don't exit immediately if it's missing during build
41
+ logger.warning("GOOGLE_API_KEY environment variable not set or is a placeholder.")
42
+ client = genai.Client(api_key=GOOGLE_API_KEY)
43
+ except (KeyError, ValueError) as e:
44
+ logger.critical(f"Error: {e}. Please set the GOOGLE_API_KEY environment variable.")
45
+ # sys.exit(1) # Don't exit, let it fail at runtime if key is missing, to allow build to pass
46
+
47
+ CONFIG = {
48
+ "response_modalities": ["AUDIO"],
49
+ "output_audio_transcription": {},
50
+ "generation_config": {
51
+ "temperature": 1.0,
52
+ },
53
+ }
54
+
55
+ # pya = pyaudio.PyAudio() # Removed pyaudio dependency
56
+
57
+ app = FastAPI()
58
+
59
+ # Mount static files
60
+ # We assume the frontend build will be copied to 'static' directory in the container
61
+ if os.path.exists("static"):
62
+ app.mount("/assets", StaticFiles(directory="static/assets"), name="assets")
63
+
64
+ @app.get("/")
65
+ async def get():
66
+ # Serve the index.html from the static directory
67
+ if os.path.exists("static/index.html"):
68
+ return FileResponse("static/index.html")
69
+ return HTMLResponse("<h1>Frontend not found. Please build the frontend.</h1>")
70
+
71
+
72
+ class AudioLoop:
73
+ def __init__(self, websocket: WebSocket):
74
+ self.websocket = websocket
75
+ self.session = None
76
+
77
+ async def run(self):
78
+ try:
79
+ async with client.aio.live.connect(model=MODEL, config=CONFIG) as session:
80
+ self.session = session
81
+ logger.info("Gemini Live API session started.")
82
+
83
+ async with asyncio.TaskGroup() as tg:
84
+ tg.create_task(self.receive_from_gemini())
85
+ tg.create_task(self.send_to_gemini())
86
+
87
+ except asyncio.CancelledError:
88
+ logger.info("Audio loop cancelled.")
89
+ except google_exceptions.GoogleAPICallError as e:
90
+ logger.error(f"Google API call error in audio loop: {e}")
91
+ await self.websocket.close(code=1011, reason=f"Google API Error: {e}")
92
+ except Exception as e:
93
+ logger.error(f"An error occurred in the audio loop: {e}")
94
+ traceback.print_exc()
95
+ await self.websocket.close(code=1011, reason="Internal Server Error")
96
+
97
+
98
+ async def send_to_gemini(self):
99
+ """Receives audio from the WebSocket and sends it to the Gemini API."""
100
+ while True:
101
+ try:
102
+ data = await self.websocket.receive_bytes()
103
+ if self.session:
104
+ await self.session.send(
105
+ input={"data": data, "mime_type": "audio/pcm"}
106
+ )
107
+ except WebSocketDisconnect:
108
+ logger.info("Client disconnected from WebSocket.")
109
+ break
110
+ except Exception as e:
111
+ logger.error(f"Error receiving from websocket or sending to Gemini: {e}")
112
+ break
113
+
114
+ async def receive_from_gemini(self):
115
+ """Receives audio and text from the Gemini API and forwards it to the WebSocket."""
116
+ while True:
117
+ try:
118
+ if self.session:
119
+ turn = self.session.receive()
120
+ async for response in turn:
121
+ # Handle audio data directly from response.data
122
+ if data := response.data:
123
+ await self.websocket.send_bytes(data)
124
+ continue
125
+
126
+ # Handle text/transcript and potentially nested audio data
127
+ candidate_texts = []
128
+ server_content = (
129
+ response.server_content.model_turn.parts
130
+ if response.server_content
131
+ and response.server_content.model_turn
132
+ and response.server_content.model_turn.parts
133
+ else []
134
+ )
135
+
136
+ for part in server_content:
137
+ # Check for nested audio data
138
+ if inline_data := getattr(part, "inline_data", None):
139
+ if data := getattr(inline_data, "data", None):
140
+ await self.websocket.send_bytes(data)
141
+ # Check for text
142
+ if part_text := getattr(part, "text", None):
143
+ candidate_texts.append(part_text)
144
+
145
+ server_content_obj = getattr(response, "server_content", None)
146
+ if server_content_obj:
147
+ if output_transcription := getattr(server_content_obj, "output_transcription", None):
148
+ if trans_text := getattr(output_transcription, "text", None):
149
+ candidate_texts.append(trans_text)
150
+ if input_transcription := getattr(server_content_obj, "input_transcription", None):
151
+ if trans_text := getattr(input_transcription, "text", None):
152
+ candidate_texts.append(trans_text)
153
+
154
+ if output_text := getattr(response, "output_text", None):
155
+ if isinstance(output_text, (list, tuple)):
156
+ candidate_texts.extend(output_text)
157
+ else:
158
+ candidate_texts.append(output_text)
159
+
160
+ if response_text := getattr(response, "text", None):
161
+ candidate_texts.append(response_text)
162
+
163
+ for text_chunk in candidate_texts:
164
+ if not text_chunk:
165
+ continue
166
+ normalized = text_chunk.replace("\r", "").replace("\n", " ")
167
+ if normalized and normalized.strip():
168
+ logger.info(f"Received text: {normalized.strip()}")
169
+ await self.websocket.send_text(normalized)
170
+ except WebSocketDisconnect:
171
+ logger.info("Client disconnected. Stopping receive loop.")
172
+ break
173
+ except Exception as e:
174
+ logger.error(f"Error receiving from Gemini or sending to websocket: {e}")
175
+ break
176
+
177
+
178
+ @app.websocket("/ws")
179
+ async def websocket_endpoint(websocket: WebSocket):
180
+ await websocket.accept()
181
+ logger.info("WebSocket connection accepted.")
182
+ audio_loop = AudioLoop(websocket)
183
+ try:
184
+ await audio_loop.run()
185
+ except WebSocketDisconnect:
186
+ logger.info("Client disconnected.")
187
+ except Exception as e:
188
+ logger.error(f"Error in websocket endpoint: {e}")
189
+ finally:
190
+ logger.info("WebSocket connection closed.")
techhubprototypeucbackend/requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ uvicorn>=0.30.5
2
+ google-genai==1.46.0
3
+ google-auth==2.41.1
4
+ google-api-core==2.19.2
5
+ pydantic==2.9.0
6
+ pydantic-settings==2.7.0
7
+ pytest>=8.3
8
+ pytest-asyncio>=0.23
9
+ fastapi
10
+ python-dotenv
11
+ websockets
12
+ pyaudio
techhubprototypeucbackend/tests/__pycache__/test_main.cpython-312-pytest-8.4.2.pyc ADDED
Binary file (4.9 kB). View file
 
techhubprototypeucbackend/tests/test_main.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from fastapi.testclient import TestClient
3
+ from unittest.mock import patch, MagicMock, AsyncMock
4
+ from main import app
5
+
6
+ client = TestClient(app)
7
+
8
+ def test_read_main():
9
+ response = client.get("/")
10
+ assert response.status_code == 200
11
+ assert "<h1>Gemini Live API</h1>" in response.text
12
+
13
+ @pytest.mark.asyncio
14
+ @patch('main.client')
15
+ async def test_websocket_connection(mock_client):
16
+ # Mock the Gemini client and session
17
+ mock_session = MagicMock()
18
+
19
+ # Make the mock session an async iterator for the receive method
20
+ mock_session.receive.return_value = mock_session
21
+ async def async_iterator():
22
+ yield MagicMock(text="test", data=b"")
23
+ mock_session.__aiter__.return_value = async_iterator()
24
+ mock_session.send = AsyncMock()
25
+
26
+ # Create an async context manager for the mock
27
+ async def async_context_manager(*args, **kwargs):
28
+ class AsyncContextManager:
29
+ async def __aenter__(self):
30
+ return mock_session
31
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
32
+ pass
33
+ return AsyncContextManager()
34
+
35
+ mock_client.aio.live.connect.side_effect = async_context_manager
36
+
37
+ with client.websocket_connect("/ws") as websocket:
38
+ # Test connection and initial message
39
+ assert websocket.scope['path'] == '/ws'
40
+
41
+ # Simulate sending audio data
42
+ audio_data = b'\x01\x02\x03'
43
+ websocket.send_bytes(audio_data)
44
+
45
+ # Close the connection
46
+ websocket.close()
techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2006 Hubert Pham
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/METADATA ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: PyAudio
3
+ Version: 0.2.14
4
+ Summary: Cross-platform audio I/O with PortAudio
5
+ Home-page: https://people.csail.mit.edu/hubert/pyaudio/
6
+ Author: Hubert Pham
7
+ License: MIT
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: Multimedia :: Sound/Audio
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE.txt
14
+ Provides-Extra: test
15
+ Requires-Dist: numpy ; extra == 'test'
16
+
17
+ <img align="right" width="200" style="margin-left: 3px" src="https://people.csail.mit.edu/hubert/pyaudio/images/snake-300.png">
18
+
19
+ # PyAudio
20
+
21
+ PyAudio provides Python bindings for PortAudio v19, the cross-platform audio I/O library. With PyAudio, you can easily use Python to play and record audio on a variety of platforms, such as GNU/Linux, Microsoft Windows, and Apple macOS.
22
+
23
+ PyAudio is distributed under the MIT License.
24
+
25
+ * [Homepage](https://people.csail.mit.edu/hubert/pyaudio/)
26
+ * [API Documentation](https://people.csail.mit.edu/hubert/pyaudio/docs/)
27
+ * [PyPi](https://pypi.python.org/pypi/PyAudio)
28
+
29
+ ## Installation
30
+
31
+ See the INSTALLATION file in the source distribution for details. In summary, install PyAudio using `pip` on most platforms.
32
+
33
+ ### Windows
34
+
35
+ ```sh
36
+ python -m pip install pyaudio
37
+ ```
38
+
39
+ This installs the precompiled PyAudio library with PortAudio v19 19.7.0 included. The library is compiled with support for Windows MME API, DirectSound, WASAPI, and WDM-KS. It does not include support for ASIO. If you require support for APIs not included, you will need to compile PortAudio and PyAudio.
40
+
41
+ ### macOS
42
+
43
+ Use [Homebrew](https://brew.sh) to install the prerequisite [portaudio](http://portaudio.com) library, then install PyAudio using `pip`:
44
+
45
+ ```sh
46
+ brew install portaudio
47
+ pip install pyaudio
48
+ ```
49
+
50
+ ### GNU/Linux
51
+
52
+ Use the package manager to install PyAudio. For example, on Debian-based systems:
53
+
54
+ ```sh
55
+ sudo apt install python3-pyaudio
56
+ ```
57
+
58
+ Alternatively, if the latest version of PyAudio is not available, install it using `pip`. Be sure to first install development libraries for `portaudio19` and `python3`.
59
+
60
+ ### Building from source
61
+
62
+ See the INSTALLATION file.
63
+
64
+ ## Documentation & Usage Examples
65
+
66
+ * Read the [API Documentation](https://people.csail.mit.edu/hubert/pyaudio/docs/), or generate it from the source using [`sphinx`](https://www.sphinx-doc.org/).
67
+
68
+ * Usage examples are in the `examples` directory of the source distribution, or see the [project homepage](https://people.csail.mit.edu/hubert/pyaudio/).
69
+
70
+ ## License
71
+
72
+ PyAudio is distributed under the MIT License. See LICENSE.txt.
techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/RECORD ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ PyAudio-0.2.14.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ PyAudio-0.2.14.dist-info/LICENSE.txt,sha256=fntVlrMb-hzPD2Nug0TmemhiZeCRwN02DxG2bcgqvFQ,1055
3
+ PyAudio-0.2.14.dist-info/METADATA,sha256=qNNR9Cphk7asLfQ1hbLo3VibawpPaCR2HyufgWYdrwI,2683
4
+ PyAudio-0.2.14.dist-info/RECORD,,
5
+ PyAudio-0.2.14.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ PyAudio-0.2.14.dist-info/WHEEL,sha256=7M9omTteV1AA1lqimSm66FA5mPjaJNBD3zI5eMwtk7s,102
7
+ PyAudio-0.2.14.dist-info/top_level.txt,sha256=jp8bgmWZh435lFm-DsWc00D0k4xj4iAEmWd1L_TpKk8,8
8
+ pyaudio/__init__.py,sha256=7V6ZjNJra5wjKcIoklmSU84UmFMrFm23DT1dtWtxXGU,36914
9
+ pyaudio/__pycache__/__init__.cpython-312.pyc,,
10
+ pyaudio/_portaudio.cp312-win_amd64.pyd,sha256=aKCiqugJeqIL9-m0A6N4KdufANn-sN1ea33C5_vNeBk,301568
techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/REQUESTED ADDED
File without changes
techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.41.3)
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-win_amd64
5
+
techhubprototypeucbackend/venv/Lib/site-packages/PyAudio-0.2.14.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ pyaudio
techhubprototypeucbackend/venv/Lib/site-packages/__pycache__/py.cpython-312.pyc ADDED
Binary file (549 Bytes). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ff5616ddeb9ff271cbcba20d5201ea1643c2899ba707d028dbb6e58ae95f2eaf
3
+ size 163697
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+
4
+ __all__ = ["__version__", "version_tuple"]
5
+
6
+ try:
7
+ from ._version import version as __version__
8
+ from ._version import version_tuple
9
+ except ImportError: # pragma: no cover
10
+ # broken installation, we don't even try
11
+ # unknown only works because we do poor mans version compare
12
+ __version__ = "unknown"
13
+ version_tuple = (0, 0, "unknown")
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (537 Bytes). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/_argcomplete.cpython-312.pyc ADDED
Binary file (4.88 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/_version.cpython-312.pyc ADDED
Binary file (846 Bytes). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/cacheprovider.cpython-312.pyc ADDED
Binary file (30.9 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/capture.cpython-312.pyc ADDED
Binary file (55.8 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/compat.cpython-312.pyc ADDED
Binary file (12.5 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/debugging.cpython-312.pyc ADDED
Binary file (18.3 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/deprecated.cpython-312.pyc ADDED
Binary file (2.62 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/doctest.cpython-312.pyc ADDED
Binary file (33.4 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/faulthandler.cpython-312.pyc ADDED
Binary file (4.49 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/fixtures.cpython-312.pyc ADDED
Binary file (81.9 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/freeze_support.cpython-312.pyc ADDED
Binary file (1.88 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/helpconfig.cpython-312.pyc ADDED
Binary file (12.6 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/hookspec.cpython-312.pyc ADDED
Binary file (45.7 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/junitxml.cpython-312.pyc ADDED
Binary file (33.2 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/legacypath.cpython-312.pyc ADDED
Binary file (24.2 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/logging.cpython-312.pyc ADDED
Binary file (45.9 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/main.cpython-312.pyc ADDED
Binary file (44.1 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/monkeypatch.cpython-312.pyc ADDED
Binary file (16.6 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/nodes.cpython-312.pyc ADDED
Binary file (30.9 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/outcomes.cpython-312.pyc ADDED
Binary file (11.8 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/pastebin.cpython-312.pyc ADDED
Binary file (5.92 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/pathlib.cpython-312.pyc ADDED
Binary file (41.3 kB). View file
 
techhubprototypeucbackend/venv/Lib/site-packages/_pytest/__pycache__/pytester.cpython-312.pyc ADDED
Binary file (84.5 kB). View file