Skip to content

Commit 3d08131

Browse files
authored
Implement OpenAI server (#1)
* Implement OpenAI server * Add an example client * Add use cases to the Readme * Adapt to the new open_ai srv type. Get rid of codespell. * Fix CI * Drop Jazzy CI on main branch
1 parent c9dae76 commit 3d08131

File tree

12 files changed

+628
-30
lines changed

12 files changed

+628
-30
lines changed

.clang-format

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
BasedOnStyle: Google
3+
ColumnLimit: 120
4+
MaxEmptyLinesToKeep: 1
5+
SortIncludes: false
6+
7+
Standard: Auto
8+
IndentWidth: 2
9+
TabWidth: 2
10+
UseTab: Never
11+
AccessModifierOffset: -2
12+
ConstructorInitializerIndentWidth: 2
13+
NamespaceIndentation: None
14+
ContinuationIndentWidth: 4
15+
IndentCaseLabels: true
16+
IndentFunctionDeclarationAfterType: false
17+
18+
AlignEscapedNewlinesLeft: false
19+
AlignTrailingComments: true
20+
21+
AllowAllParametersOfDeclarationOnNextLine: false
22+
ExperimentalAutoDetectBinPacking: false
23+
ObjCSpaceBeforeProtocolList: true
24+
Cpp11BracedListStyle: false
25+
26+
AllowShortBlocksOnASingleLine: true
27+
AllowShortIfStatementsOnASingleLine: false
28+
AllowShortLoopsOnASingleLine: false
29+
AllowShortFunctionsOnASingleLine: None
30+
AllowShortCaseLabelsOnASingleLine: false
31+
32+
AlwaysBreakTemplateDeclarations: true
33+
AlwaysBreakBeforeMultilineStrings: false
34+
BreakBeforeBinaryOperators: false
35+
BreakBeforeTernaryOperators: false
36+
BreakConstructorInitializersBeforeComma: true
37+
38+
BinPackParameters: true
39+
ConstructorInitializerAllOnOneLineOrOnePerLine: true
40+
DerivePointerBinding: false
41+
PointerBindsToType: true
42+
43+
PenaltyExcessCharacter: 50
44+
PenaltyBreakBeforeFirstCallParameter: 30
45+
PenaltyBreakComment: 1000
46+
PenaltyBreakFirstLessLess: 10
47+
PenaltyBreakString: 100
48+
PenaltyReturnTypeOnItsOwnLine: 50
49+
50+
SpacesBeforeTrailingComments: 2
51+
SpacesInParentheses: false
52+
SpacesInAngles: false
53+
SpaceInEmptyParentheses: false
54+
SpacesInCStyleCastParentheses: false
55+
SpaceAfterCStyleCast: false
56+
SpaceAfterControlStatementKeyword: true
57+
SpaceBeforeAssignmentOperators: true
58+
59+
# Configure each individual brace in BraceWrapping
60+
BreakBeforeBraces: Custom
61+
62+
# Qualifiers (const, volatile, static, etc)
63+
QualifierAlignment: Custom
64+
QualifierOrder: ['static', 'inline', 'constexpr', 'const', 'volatile', 'type']
65+
66+
# Control of individual brace wrapping cases
67+
BraceWrapping:
68+
AfterCaseLabel: true
69+
AfterClass: true
70+
AfterControlStatement: true
71+
AfterEnum: true
72+
AfterFunction: true
73+
AfterNamespace: true
74+
AfterStruct: true
75+
AfterUnion: true
76+
BeforeCatch: true
77+
BeforeElse: true
78+
IndentBraces: false
79+
...

.clang-tidy

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
Checks: '-*,
3+
performance-*,
4+
-performance-enum-size,
5+
llvm-namespace-comment,
6+
modernize-redundant-void-arg,
7+
modernize-use-nullptr,
8+
modernize-use-default,
9+
modernize-use-override,
10+
modernize-loop-convert,
11+
modernize-make-shared,
12+
modernize-make-unique,
13+
modernize-avoid-bind,
14+
misc-unused-parameters,
15+
readability-braces-around-statements,
16+
readability-named-parameter,
17+
readability-redundant-smartptr-get,
18+
readability-redundant-string-cstr,
19+
readability-simplify-boolean-expr,
20+
readability-container-size-empty,
21+
readability-identifier-naming,
22+
readability-static-definition-in-anonymous-namespace,
23+
'
24+
HeaderFilterRegex: ''
25+
CheckOptions:
26+
- key: llvm-namespace-comment.ShortNamespaceLines
27+
value: '10'
28+
- key: llvm-namespace-comment.SpacesBeforeComments
29+
value: '2'
30+
- key: misc-unused-parameters.StrictMode
31+
value: '1'
32+
- key: readability-braces-around-statements.ShortStatementLines
33+
value: '2'
34+
# type names
35+
- key: readability-identifier-naming.ClassCase
36+
value: CamelCase
37+
- key: readability-identifier-naming.EnumCase
38+
value: CamelCase
39+
- key: readability-identifier-naming.UnionCase
40+
value: CamelCase
41+
# function names
42+
- key: readability-identifier-naming.FunctionCase
43+
value: camelBack
44+
# method names
45+
- key: readability-identifier-naming.MethodCase
46+
value: camelBack
47+
# variable names
48+
- key: readability-identifier-naming.VariableCase
49+
value: lower_case
50+
- key: readability-identifier-naming.ProtectedMemberSuffix
51+
value: '_'
52+
- key: readability-identifier-naming.PrivateMemberSuffix
53+
value: '_'
54+
# const static or global variables are UPPER_CASE
55+
- key: readability-identifier-naming.EnumConstantCase
56+
value: UPPER_CASE
57+
- key: readability-identifier-naming.StaticVariableCasePrefix
58+
value: 's_'
59+
- key: readability-identifier-naming.StaticConstantCase
60+
value: UPPER_CASE
61+
- key: readability-identifier-naming.GlobalConstantCase
62+
value: UPPER_CASE
63+
- key: readability-identifier-naming.ClassConstantCase
64+
value: UPPER_CASE
65+
...

.github/workflows/build.yml

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,18 @@
1-
# This is a basic workflow to help you get started with Actions
2-
31
name: CI
42

5-
# Controls when the workflow will run
6-
on:
7-
# Triggers the workflow on push or pull request events but only for the "main" branch
8-
push:
9-
branches: [ "main" ]
10-
pull_request:
11-
branches: [ "main" ]
12-
13-
# Allows you to run this workflow manually from the Actions tab
14-
workflow_dispatch:
3+
on: [push, pull_request]
154

16-
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
175
jobs:
18-
# This workflow contains a single job called "build"
19-
build:
20-
# The type of runner that the job will run on
6+
industrial_ci:
7+
strategy:
8+
matrix:
9+
env:
10+
- {ROS_DISTRO: humble, ROS_REPO: main}
2111
runs-on: ubuntu-latest
22-
23-
# Steps represent a sequence of tasks that will be executed as part of the job
12+
env:
13+
UPSTREAM_WORKSPACE: upstream.repos
14+
AFTER_SETUP_UPSTREAM_WORKSPACE: sudo apt update && sudo apt install -y libcurl4-openssl-dev nlohmann-json3-dev libb64-dev
2415
steps:
25-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
26-
- uses: actions/checkout@v4
27-
28-
# Runs a single command using the runners shell
29-
- name: Run a one-line script
30-
run: echo Hello, world!
31-
32-
# Runs a set of commands using the runners shell
33-
- name: Run a multi-line script
34-
run: |
35-
echo Add other actions to build,
36-
echo test, and deploy your project.
16+
- uses: actions/checkout@v3
17+
- uses: 'ros-industrial/industrial_ci@master'
18+
env: ${{matrix.env}}

.pre-commit-config.yaml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# To use:
2+
#
3+
# pre-commit run -a
4+
#
5+
# Or:
6+
#
7+
# pre-commit install # (runs every time you commit in git)
8+
#
9+
# To update this file:
10+
#
11+
# pre-commit autoupdate
12+
#
13+
# See https://github.com/pre-commit/pre-commit
14+
15+
repos:
16+
# Standard hooks
17+
- repo: https://github.com/pre-commit/pre-commit-hooks
18+
rev: v4.5.0
19+
hooks:
20+
- id: check-added-large-files
21+
- id: check-case-conflict
22+
- id: check-json
23+
- id: check-merge-conflict
24+
- id: check-symlinks
25+
- id: check-toml
26+
- id: check-yaml
27+
- id: debug-statements
28+
- id: destroyed-symlinks
29+
- id: detect-private-key
30+
- id: end-of-file-fixer
31+
- id: mixed-line-ending
32+
- id: pretty-format-json
33+
- id: trailing-whitespace
34+
35+
- repo: https://github.com/psf/black
36+
rev: 23.10.0
37+
hooks:
38+
- id: black
39+
40+
- repo: local
41+
hooks:
42+
- id: clang-format
43+
name: clang-format
44+
description: Format files with ClangFormat.
45+
entry: clang-format-14
46+
language: system
47+
files: \.(c|cc|cxx|cpp|frag|glsl|h|hpp|hxx|ih|ispc|ipp|java|js|m|proto|vert)$
48+
args: ['-fallback-style=none', '-i']
49+
50+
- repo: https://github.com/cheshirekow/cmake-format-precommit
51+
rev: v0.6.10
52+
hooks:
53+
- id: cmake-format
54+
- id: cmake-lint
55+
args:
56+
- "--disabled-codes=C0301" # Disable Line too long lint
57+
- "--suppress-decorations"

CMakeLists.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
project(ros2_openai_server)
3+
4+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
5+
add_compile_options(-Wall -Wextra -Wpedantic)
6+
endif()
7+
8+
set(THIS_PACKAGE_INCLUDE_DEPENDS ai_msgs cv_bridge rclcpp sensor_msgs)
9+
10+
find_package(ament_cmake REQUIRED)
11+
find_package(CURL REQUIRED)
12+
find_package(nlohmann_json REQUIRED)
13+
find_package(OpenCV REQUIRED)
14+
foreach(dependency IN ITEMS ${THIS_PACKAGE_INCLUDE_DEPENDS})
15+
find_package(${dependency} REQUIRED)
16+
endforeach()
17+
18+
find_package(ament_cmake REQUIRED)
19+
20+
include_directories(include)
21+
22+
add_executable(openai_server src/openai_server.cpp)
23+
ament_target_dependencies(openai_server ${THIS_PACKAGE_INCLUDE_DEPENDS})
24+
target_link_libraries(openai_server b64 CURL::libcurl nlohmann_json
25+
${OpenCV_LIBS})
26+
27+
add_executable(example_client src/example_client.cpp)
28+
ament_target_dependencies(example_client ${THIS_PACKAGE_INCLUDE_DEPENDS})
29+
target_link_libraries(example_client ${OpenCV_LIBS})
30+
31+
install(
32+
TARGETS example_client openai_server
33+
ARCHIVE DESTINATION lib
34+
LIBRARY DESTINATION lib
35+
RUNTIME DESTINATION lib/ros2_openai_server)
36+
37+
install(DIRECTORY include DESTINATION include/ros2_openai_server)
38+
install(
39+
DIRECTORY test_data
40+
DESTINATION DESTINATION
41+
share/ros2_openai_server)
42+
43+
ament_export_dependencies(rosidl_default_runtime)
44+
ament_package()

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,49 @@
11
# ros2_openai_server
2+
23
OpenAI server node for ROS2 Applications
4+
5+
## What is this useful for?
6+
7+
If you don't have an image processing pipeline or a GPU on your robot, calls to OpenAI can replace much of that functionality. As of July 2024 we generally recommend yes/no questions, otherwise you will need to parse the response yourself. This package includes a simple filter which parses for yes/no. For example:
8+
9+
- Is it safe for the robot to drive forward? Please respond in one word, yes or no.
10+
- Is the door open? Please respond in one word, yes or no.
11+
- Is there a customer at that table? Please respond in one word, yes or no.
12+
- Did the robot successfully grasp the cube? Please respond in one word, yes or no.
13+
- Does the control panel look identical to the last time I checked? Please respond in one word, yes or no.
14+
15+
Some of these examples are useful for reinforcement learning, i.e. for determining if a reward was earned.
16+
17+
## Setup
18+
19+
Requires an OpenAI key as described here: https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key
20+
21+
Set it as an environment variable: `export OPENAI_API_KEY="..."`
22+
23+
### Dependencies
24+
25+
`sudo apt install -y libcurl4-openssl-dev nlohmann-json3-dev libb64-dev`
26+
27+
## Run
28+
29+
Here's a quick example:
30+
31+
`ros2 run ros2_openai_server openai_server`
32+
33+
Send it a prompt. Here's an example that returns a bool from a yes/no question. Not that the `image` field of the service request may be left empty.
34+
35+
`ros2 service call /openai_server ai_msgs/srv/BoolResponse prompt:\ "Are you a pirate? Please respond with a one-word answer, yes or no"`
36+
37+
Here's an example that returns a full string.
38+
39+
`ros2 service call /openai_string_response ai_msgs/srv/StringResponse prompt:\ "Are you a pirate?"`
40+
41+
There's an example client which sends an image of a wooden table and prompts whether it is indeed a wooden table:
42+
43+
`ros2 run ros2_openai_server example_client`
44+
45+
## Citation
46+
47+
If you use this work, please cite it like so:
48+
49+
- Zelenak, A., Lock, J., & Aldrich, B. (2024) *An OpenAI Server for ROS2*. Github. **https://github.com/robosoft-ai/ros2_openai_server**

0 commit comments

Comments
 (0)