Untitled
unknown
plain_text
10 months ago
16 kB
18
Indexable
import os
import asyncio
import base64
import io
import traceback
import cv2
import pyaudio
import PIL.Image
import mss
import argparse
from google import genai
from google.genai import types
from dotenv import load_dotenv
import subprocess
import sys
import time # EKLE
game_process = {}
load_dotenv()
FORMAT = pyaudio.paInt16
CHANNELS = 1
SEND_SAMPLE_RATE = 16000
RECEIVE_SAMPLE_RATE = 24000
CHUNK_SIZE = 1024
camera_state = False
main = None
MODEL = "models/gemini-2.5-flash-live-preview"
DEFAULT_MODE = "all"
client = genai.Client(
http_options={"api_version": "v1beta"},
api_key=os.environ.get("GOOGLE_API_KEY"),
)
async def start_game(dosya_adi: str):
try:
python_path = sys.executable
full_path = os.path.abspath(dosya_adi)
working_dir = os.path.dirname(full_path) # Çalışma dizini olarak klasörünü al
proses = subprocess.Popen(
[python_path, full_path],
cwd=working_dir
)
game_process[dosya_adi] = proses
print(f"{dosya_adi} başlatıldı. PID: {proses.pid}")
except Exception as e:
print(f"Hata oluştu: {e}")
async def stop_game(dosya_adi: str):
proses = game_process.get(dosya_adi)
if proses and proses.poll() is None:
proses.terminate()
print(f"{dosya_adi} durduruldu.")
return f"Oyun durduruldu: {dosya_adi}"
else:
print(f"{dosya_adi} zaten çalışmıyor.")
return f"Oyun zaten çalışmıyor: {dosya_adi}"
async def draw_game_start_stop(durum: bool):
if durum:
await main.stop_camera()
print("oyun başladı")
await start_game("test_projects/Games/AI-Virtual-Paint-main/Ai_virtual_painter.py")
return "Çizim oyunu başlatıldı!"
else:
await stop_game("test_projects/Games/AI-Virtual-Paint-main/Ai_virtual_painter.py")
print("oyun durdu")
await main.start_camera()
print("kamera başlatıldı")
return "Çizim oyunu durduruldu!"
tools = [
types.Tool(
function_declarations=[
types.FunctionDeclaration(
name="draw_game_start_stop",
description="Resim çizme oyununu başlatır veya durdurur.",
parameters=genai.types.Schema(
type=genai.types.Type.OBJECT,
required=["durum"],
properties={
"durum": genai.types.Schema(
type=genai.types.Type.BOOLEAN,
),
},
),
),
]
),
]
AVAILABLE_TOOLS = {
"draw_game_start_stop": draw_game_start_stop,
}
CONFIG = types.LiveConnectConfig(
response_modalities=[
"AUDIO",
],
media_resolution="MEDIA_RESOLUTION_MEDIUM",
speech_config=types.SpeechConfig(
language_code="tr-TR",
voice_config=types.VoiceConfig(
prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name="Puck")
)
),
context_window_compression=types.ContextWindowCompressionConfig(
trigger_tokens=25600,
sliding_window=types.SlidingWindow(target_tokens=12800),
),
system_instruction=types.Content(
parts=[types.Part.from_text(text=
"Senin adın 'Jollyboo'. Artık küçük çocuklarla konuşan nazik, arkadaş canlısı ve neşeli bir karakter gibi davranacaksın."
)],
role="system"
),
tools=tools,
)
pya = pyaudio.PyAudio()
class AudioLoop:
def __init__(self, video_mode=DEFAULT_MODE):
self.video_mode = video_mode
self.audio_in_queue = None
self.out_queue = None
self.session = None
self.send_text_task = None
self.receive_audio_task = None
self.play_audio_task = None
self.is_talking = False
self._talking_reset_task = None
self.normal_face = cv2.imread("main_assets/faces/normal_face.png")
self.talking_face = cv2.imread("main_assets/faces/talking_face.png")
self.camera_state = True
self.camera_stopped_event = asyncio.Event()
self._suppress_mic_until = 0.0 # model ses çalarken mikrofona kilit
self._playback_active = False
async def start_camera(self):
if not camera_state:
asyncio.create_task(self.get_frames())
async def stop_camera(self):
global camera_state
camera_state = False
self.camera_stopped_event.clear()
print("Kamera durması bekleniyor...")
await self.camera_stopped_event.wait()
print("Kamera durdu ve kaynak serbest.")
async def send_text(self):
while True:
text = await asyncio.to_thread(
input,
"message > ",
)
if text.lower() == "q":
break
await self.session.send(input=text or ".", end_of_turn=True)
@staticmethod
def _get_frame(cap):
ret, frame = cap.read()
if not ret:
return None
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = PIL.Image.fromarray(frame_rgb)
img.thumbnail([1024, 1024])
image_io = io.BytesIO()
img.save(image_io, format="jpeg")
image_io.seek(0)
mime_type = "image/jpeg"
image_bytes = image_io.read()
return {"mime_type": mime_type, "data": base64.b64encode(image_bytes).decode()}
async def get_frames(self):
print("[DEBUG] Kamera başlatılıyor...")
cap = await asyncio.to_thread(cv2.VideoCapture, 0)
global camera_state
camera_state = True
while True:
frame = await asyncio.to_thread(self._get_frame, cap)
if not camera_state:
print("[DEBUG] Kamera durma isteği geldi.")
break
if frame is None:
break
await asyncio.sleep(1.0)
await self.out_queue.put(frame)
print("[DEBUG] Kamera kapatılıyor...")
cap.release()
self.camera_stopped_event.set()
print("[LOG] Kamera kaynağı serbest bırakıldı.")
@staticmethod
def _get_screen():
sct = mss.mss()
monitor = sct.monitors[0]
i = sct.grab(monitor)
mime_type = "image/jpeg"
image_bytes = mss.tools.to_png(i.rgb, i.size)
img = PIL.Image.open(io.BytesIO(image_bytes))
image_io = io.BytesIO()
img.save(image_io, format="jpeg")
image_io.seek(0)
image_bytes = image_io.read()
return {"mime_type": mime_type, "data": base64.b64encode(image_bytes).decode()}
async def get_screen(self):
while True:
frame = await asyncio.to_thread(self._get_screen)
if frame is None:
break
await asyncio.sleep(1.0)
await self.out_queue.put(frame)
async def send_realtime(self):
while True:
msg = await self.out_queue.get()
await self.session.send(input=msg)
async def listen_audio(self):
mic_info = pya.get_default_input_device_info()
self.audio_stream = await asyncio.to_thread(
pya.open,
format=FORMAT,
channels=CHANNELS,
rate=SEND_SAMPLE_RATE,
input=True,
input_device_index=mic_info["index"],
frames_per_buffer=CHUNK_SIZE,
)
kwargs = {"exception_on_overflow": False} if __debug__ else {}
while True:
data = await asyncio.to_thread(self.audio_stream.read, CHUNK_SIZE, **kwargs)
# ⭐ Model ses çalarken ve hemen sonrasında mikrofondan geleni YOLLAMA
now = time.monotonic()
if self.is_talking or now < self._suppress_mic_until:
continue
await self.out_queue.put({"data": data, "mime_type": "audio/pcm;rate=16000"})
async def receive_audio(self):
while True:
turn = self.session.receive()
async for response in turn:
if data := response.data:
self.audio_in_queue.put_nowait(data)
if text := response.text:
print("metin verisi geldi")
print(text, end="")
result_message = ""
if response.tool_call and response.tool_call.function_calls:
print(f"Model bir araç çağrısı önerdi.")
tool_output_results = []
for function_call in response.tool_call.function_calls:
function_name = function_call.name
args = function_call.args
print(f"\nModel bir fonksiyon çağırdı: {function_name} ({args})")
if function_name in AVAILABLE_TOOLS:
function_to_call = AVAILABLE_TOOLS[function_name]
try:
result_message = await function_to_call(**args)
print(f">> Araç çağrısı sonucu: {result_message}")
tool_output_results.append(
types.FunctionResponse(
name=function_name,
response={"result": result_message},
id=function_call.id
)
)
except TypeError as e:
error_msg = f"Hata: {function_name} çağrılırken argüman hatası: {e}. Argümanlar: {args}"
print(f">> {error_msg}")
tool_output_results.append(
types.FunctionResponse(
name=function_name,
response={"result": result_message},
id=function_call.id
)
)
except Exception as e:
error_msg = f"Hata: {function_name} çağrılırken bilinmeyen hata: {e}"
print(f">> {error_msg}")
tool_output_results.append(
types.FunctionResponse(
name=function_name,
response={"result": result_message},
id=function_call.id
)
)
else:
error_msg = f"Hata: Tanımlı olmayan fonksiyon çağrısı: {function_name}"
print(f">> {error_msg}")
tool_output_results.append(
types.FunctionResponse(
name=function_name,
response={"result": result_message},
id=function_call.id
)
)
if tool_output_results:
await self.session.send_tool_response(
function_responses=tool_output_results,
)
while not self.audio_in_queue.empty():
self.audio_in_queue.get_nowait()
async def _reset_talking_flag_after_delay(self, delay=0.5):
await asyncio.sleep(delay)
self.is_talking = False
async def play_audio(self):
stream = await asyncio.to_thread(
pya.open,
format=FORMAT,
channels=CHANNELS,
rate=RECEIVE_SAMPLE_RATE,
output=True,
)
while True:
bytestream = await self.audio_in_queue.get()
self.is_talking = True
self._playback_active = True
# varsa önceki reset görevini iptal et ve 0.5 sn sonra "konuşmuyor" bayrağını düşür
if self._talking_reset_task is not None:
self._talking_reset_task.cancel()
self._talking_reset_task = asyncio.create_task(self._reset_talking_flag_after_delay())
# ⭐ Ses çalarken ve hemen sonrasında mikrofonu kilitle (eko önleme penceresi)
self._suppress_mic_until = time.monotonic() + 0.35 # 350ms tampon
await asyncio.to_thread(stream.write, bytestream)
# kısa bir güvenlik tamponu daha
self._suppress_mic_until = time.monotonic() + 0.35
self._playback_active = False
async def show_face(self):
while True:
if self.is_talking:
img = self.talking_face
else:
img = self.normal_face
if img is not None:
cv2.namedWindow("Yapay Zeka Yüzü", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Yapay Zeka Yüzü", cv2.WND_PROP_FULLSCREEN, cv2.WND_PROP_FULLSCREEN)
cv2.imshow("Yapay Zeka Yüzü", img)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
await asyncio.sleep(0.1)
cv2.destroyAllWindows()
async def run(self):
try:
async with (
client.aio.live.connect(model=MODEL, config=CONFIG) as session,
asyncio.TaskGroup() as tg,
):
self.session = session
self.audio_in_queue = asyncio.Queue()
self.out_queue = asyncio.Queue(maxsize=5)
send_text_task = tg.create_task(self.send_text())
tg.create_task(self.send_realtime())
tg.create_task(self.listen_audio())
if self.video_mode == "camera":
tg.create_task(self.get_frames())
elif self.video_mode == "screen":
tg.create_task(self.get_screen())
elif self.video_mode == "all":
tg.create_task(self.get_frames())
tg.create_task(self.get_screen())
tg.create_task(self.receive_audio())
tg.create_task(self.play_audio())
# Burada yüz gösterme görevini başlatıyoruz
tg.create_task(self.show_face())
await send_text_task
raise asyncio.CancelledError("User requested exit")
except asyncio.CancelledError:
pass
except ExceptionGroup as EG:
self.audio_stream.close()
traceback.print_exception(EG)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--mode",
type=str,
default=DEFAULT_MODE,
help="pixels to stream from",
choices=["camera", "screen", "all","none"],
)
args = parser.parse_args()
main = AudioLoop(video_mode=args.mode)
asyncio.run(main.run())Editor is loading...
Leave a Comment