Skip to content

Commit 9a3147b

Browse files
authored
Merge pull request #87 from B-AROL-O/feat/mcp-pupper
feat: make FREISA-GPT main code public
2 parents e353f1d + 3b88ade commit 9a3147b

22 files changed

Lines changed: 3693 additions & 2 deletions

.devcontainer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM ghcr.io/tiryoh/ros2-desktop-vnc:humble-20250831T0421
1+
FROM ghcr.io/tiryoh/ros2-desktop-vnc:humble
22

33
ARG USERNAME
44

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "code/mcp-client-pupper/ros-mcp-server"]
2+
path = code/mcp-client-pupper/ros-mcp-server
3+
url = https://github.com/davmacario/ros-mcp-server.git

code/FREISA-GPT/.flake8

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[flake8]
2+
max-line-length = 120
3+
extend-ignore = E203,E701

code/FREISA-GPT/.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

code/FREISA-GPT/README.md

Whitespace-only changes.

code/FREISA-GPT/main.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import asyncio
2+
import os
3+
from argparse import ArgumentParser
4+
from pathlib import Path
5+
6+
from dotenv import load_dotenv
7+
8+
from src.mcp_client_pupper.main import main
9+
from src.mcp_client_pupper.puppy_voice_assistant import PuppyVoiceAssistant
10+
11+
BASE_URL = "https://open-webui.dmhosted.duckdns.org"
12+
DEFAULT_MODEL = "gpt-oss:20b"
13+
ROSBRIDGE_ADDRESS = "ws://localhost:9090"
14+
DEFAULT_PUPPY_API_URL = "http://localhost:5080"
15+
16+
if __name__ == "__main__":
17+
load_dotenv()
18+
parser = ArgumentParser()
19+
parser.add_argument(
20+
"--llm-base-url",
21+
type=str,
22+
help="Base URL to reach the LLM (without path)",
23+
default=os.getenv("OPENAI_BASE_URL", BASE_URL),
24+
)
25+
parser.add_argument(
26+
"--llm-model",
27+
type=str,
28+
help="LLM model. To be chosen among the ones available at the specified `--llm-base-url`",
29+
default=os.getenv("OPENAI_MODEL", DEFAULT_MODEL),
30+
)
31+
parser.add_argument(
32+
"--mcp-server-config",
33+
type=Path,
34+
help="Path to the MCP server configuration JSON file.",
35+
default=Path("./servers_config.json"),
36+
)
37+
parser.add_argument(
38+
"--puppy-api-url",
39+
type=str,
40+
help="URL of the HTTP API for the Puppy State API",
41+
default=os.getenv("PUPPY_API_URL", DEFAULT_PUPPY_API_URL),
42+
)
43+
parser.add_argument(
44+
"--input-device",
45+
type=int,
46+
default=1,
47+
help=f"Id of The input device (aka microphone)\navailable devices {PuppyVoiceAssistant.available_devices()}",
48+
)
49+
parser.add_argument(
50+
"--whisper-model",
51+
default="small.en",
52+
type=str,
53+
help="Whisper.cpp model, default to %(default)s",
54+
)
55+
parser.add_argument(
56+
"--silence-threshold",
57+
default=16,
58+
type=int,
59+
help="The duration of silence after which the inference will be running, defaults to %(default)s",
60+
)
61+
parser.add_argument(
62+
"--block-duration",
63+
default=30,
64+
help="Minimum time audio updates in ms, default to %(default)s",
65+
)
66+
parser.add_argument( # TODO: remove; it is only used in MCP Server
67+
"--rosbridge-address",
68+
type=str,
69+
help="Address of the websocket on which rosbridge is exposed. Format: 'ws://<address>:<port>'",
70+
default=os.getenv("ROSBRIDGE_ADDRESS", ROSBRIDGE_ADDRESS),
71+
)
72+
args = parser.parse_args()
73+
74+
asyncio.run(main(args))

code/FREISA-GPT/pyproject.toml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[project]
2+
name = "FREISA-GPT"
3+
version = "0.1.0"
4+
description = ""
5+
readme = "README.md"
6+
requires-python = ">=3.13"
7+
dependencies = [
8+
"fastapi-mcp>=0.2.0",
9+
"httpx>=0.28.1",
10+
"linkup-sdk>=0.2.4",
11+
"fastmcp>=2.11.3",
12+
"mcp[cli]>=1.13.0",
13+
"opencv-python>=4.11.0.86",
14+
"pillow>=11.3.0",
15+
"websocket-client>=1.8.0",
16+
"flask>=3.1.2",
17+
"icecream>=2.1.5",
18+
"marimo>=0.14.16",
19+
"openai>=1.99.5",
20+
"python-dotenv>=1.1.1",
21+
"pywhispercpp",
22+
"setuptools>=80.9.0",
23+
"sounddevice>=0.5.2",
24+
"soundfile>=0.13.1",
25+
"webrtcvad>=2.0.10",
26+
]
27+
28+
[dependency-groups]
29+
dev = [
30+
"pyright>=1.1.405",
31+
"ruff>=0.13.0",
32+
]
33+
34+
[tool.ruff]
35+
line-length = 120
36+
indent-width = 4
37+
38+
[tool.ruff.lint]
39+
extend-select = ["I"]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"mcpServers": {
3+
"ros-mcp-server": {
4+
"command": "uv",
5+
"args": [
6+
"--directory",
7+
"./src/mcp_server_pupper",
8+
"run",
9+
"main.py",
10+
"--mcp-transport",
11+
"stdio"
12+
]
13+
}
14+
}
15+
}

code/FREISA-GPT/src/mcp_client_pupper/__init__.py

Whitespace-only changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import logging
2+
import os
3+
4+
from .mcp_client import ChatSessionConfig
5+
from .puppy_voice_assistant import PuppyVoiceAssistant, VoiceConfig
6+
from .utils.llm_client import LLMClientConfig
7+
8+
"""
9+
FREISA-GPT entrypoint
10+
"""
11+
12+
13+
logging.basicConfig(
14+
level=os.getenv("FREISA_LOG_LEVEL", "DEBUG"),
15+
format="%(asctime)s [%(levelname)-8s] [%(name)s]: %(message)s",
16+
datefmt="%Y-%m-%d %H:%M:%S",
17+
)
18+
19+
20+
async def main(args):
21+
api_key = os.getenv("OPENAI_API_KEY")
22+
23+
chat_config = ChatSessionConfig(
24+
mcp_server_config_file=args.mcp_server_config,
25+
llm_client_config=LLMClientConfig(base_url=args.llm_base_url, model=args.llm_model, api_key=api_key),
26+
)
27+
voice_config = VoiceConfig(
28+
model=args.whisper_model,
29+
input_device=args.input_device,
30+
silence_threshold=args.silence_threshold,
31+
block_duration=args.block_duration,
32+
)
33+
voice_assistant = PuppyVoiceAssistant(voice_config, chat_config, args.puppy_api_url)
34+
await voice_assistant.set_up_mcp_client()
35+
voice_assistant.start()

0 commit comments

Comments
 (0)