File size: 5,227 Bytes
3a53236 4b91f83 3a53236 1258e4a 3a53236 1258e4a 68b7034 1258e4a 68b7034 1258e4a 3a53236 add507c 3a53236 add507c 3a53236 1258e4a 3a53236 4b91f83 3a53236 1258e4a 68b7034 1258e4a 4b91f83 3a53236 1258e4a 68b7034 1258e4a 3a53236 4b91f83 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | """IOAI — Interactive Omnivocal Audio Interpreter (CPU / free tier)."""
from __future__ import annotations
import logging
import os
import tempfile
# Workaround: gradio_client bool schema bug in get_api_info (Gradio 5.9.x)
import gradio_client.utils as client_utils
_orig_get_type = client_utils.get_type
_orig_json_schema_to_python_type = client_utils._json_schema_to_python_type
def _patched_get_type(schema):
if isinstance(schema, bool):
return "bool"
return _orig_get_type(schema)
def _patched_json_schema_to_python_type(schema, defs=None):
if isinstance(schema, bool):
return "Any" if schema else "Never"
return _orig_json_schema_to_python_type(schema, defs)
client_utils.get_type = _patched_get_type
client_utils._json_schema_to_python_type = _patched_json_schema_to_python_type
import gradio as gr
from ioai.pipeline import SessionState, process_audio, regenerate_audio
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger("ioai.app")
WORK_DIR = os.getenv("IOAI_WORK_DIR", tempfile.mkdtemp(prefix="ioai_"))
def run(audio: str | None):
if not audio:
raise gr.Error("Запишите или загрузите звук (минимум 0.5 с).")
try:
result = process_audio(audio, WORK_DIR)
except ValueError as exc:
raise gr.Error(str(exc)) from exc
except Exception as exc:
logger.exception("Pipeline failed")
raise gr.Error(f"Ошибка обработки: {exc}") from exc
details = (
f"**Язык:** {result.language}\n\n"
f"**Акустический профиль:** {result.acoustic_summary}\n\n"
f"**Основание:** {result.reasoning}"
)
return (
result.transcription,
result.reply,
result.response_audio_path,
details,
result.session,
)
def regen(session: SessionState | None, transcription: str, reply: str, mode: str):
try:
path = regenerate_audio(session, transcription, reply, WORK_DIR, mode=mode)
except ValueError as exc:
raise gr.Error(str(exc)) from exc
except Exception as exc:
logger.exception("Regeneration failed")
raise gr.Error(f"Ошибка перегенерации: {exc}") from exc
return path
DESCRIPTION = """
# IOAI — Interactive Omnivocal Audio Interpreter
**Любой звук читается как речь.** Голос, инструмент, шум, дыхание, тишина —
система извлекает *сообщение*, транскрибирует его и отвечает **тем же акустическим веществом**.
### Free tier пайплайн (CPU)
1. **Perceive** — Whisper tiny + спектральный анализ
2. **Interpret** — Qwen2.5-0.5B отвечает по смыслу распознанной речи; иначе шаблоны
3. **Synthesize** — речь (espeak + тембр) при диалоговом ответе, иначе гранулы
> Первый ответ на вопрос вроде «как дела?» теперь осмысленный и озвучен. Шаблоны остаются для шума и тишины.
"""
with gr.Blocks(title="IOAI") as demo:
gr.Markdown(DESCRIPTION)
session_state = gr.State(value=None)
with gr.Row():
with gr.Column():
audio_in = gr.Audio(label="Входящий звук", type="filepath")
btn = gr.Button("Слушать и ответить", variant="primary")
with gr.Column():
transcription = gr.Textbox(
label="Транскрипция сообщения",
lines=4,
interactive=True,
placeholder="Можно редактировать после анализа…",
)
reply = gr.Textbox(
label="Текстовый ответ",
lines=3,
interactive=True,
placeholder="Напишите «привет» или свой ответ…",
)
regen_mode = gr.Radio(
choices=[
("Речь — произносит текст", "speech"),
("Зерна — поэтичный тембр", "grain"),
],
value="speech",
label="Режим перегенерации",
)
btn_regen = gr.Button("Перегенерировать звук", variant="secondary")
audio_out = gr.Audio(label="Звуковой ответ (тот же тембр)", type="filepath", interactive=False)
details = gr.Markdown()
btn.click(
run,
inputs=[audio_in],
outputs=[transcription, reply, audio_out, details, session_state],
)
btn_regen.click(
regen,
inputs=[session_state, transcription, reply, regen_mode],
outputs=[audio_out],
)
if __name__ == "__main__":
demo.queue(max_size=4).launch(
server_name="0.0.0.0",
server_port=7860,
ssr_mode=False,
)
|