├── .bumpversion.cfg ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── stale.yml └── workflows │ ├── build-test.yml │ ├── deploy.yml │ └── integration-test.yml ├── .gitignore ├── .releaserc ├── .rubocop.yml ├── .secrets.baseline ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── MIGRATION-V2.md ├── MIGRATION-v1.md ├── README.md ├── bin ├── console └── setup ├── docker ├── Dockerfile └── README.md ├── examples ├── README.md ├── assistant_v1.rb ├── assistant_v2.rb ├── compare_comply_v1.rb ├── discovery_v1.rb ├── discovery_v2.rb ├── language_translator_v3.rb ├── natural_language_classifier_v1.rb ├── natural_language_understanding_v1.rb ├── personality_insights_v3.rb ├── speech_to_text_v1.rb ├── text_to_speech_v1.rb ├── tone_analyzer_v3.rb ├── visual_recognition_v3.rb └── visual_recognition_v4.rb ├── ibm_watson.gemspec ├── lib ├── ibm_watson.rb └── ibm_watson │ ├── assistant_v1.rb │ ├── assistant_v2.rb │ ├── authenticators.rb │ ├── common.rb │ ├── discovery_v1.rb │ ├── discovery_v2.rb │ ├── language_translator_v3.rb │ ├── natural_language_understanding_v1.rb │ ├── speech_to_text_v1.rb │ ├── text_to_speech_v1.rb │ ├── version.rb │ └── websocket │ ├── recognize_callback.rb │ └── speech_to_text_websocket_listener.rb ├── rakefile ├── resources ├── car.jpg ├── language_translator_model.tmx ├── nlu_categories_training.json ├── nlu_classifications_training.json ├── nlu_sentiment_data.csv ├── personality-v3-expect2.txt ├── personality-v3.json ├── personality.txt ├── problem.json ├── simple.html ├── sound-with-pause.wav ├── speech.wav ├── speech_to_text │ ├── corpus-full.txt │ ├── corpus-short-1.txt │ └── corpus-short-2.txt ├── test_enrichments.csv ├── tone-example-html.json ├── tone-example.json ├── tone-v3-expect1.json ├── tone-v3-expect2.json ├── translation_doc.txt └── weather_data_train.csv ├── scripts ├── ruby-tasks │ ├── rakefile │ ├── speech_to_text_v1.rake │ └── speech_to_text_v1 │ │ └── recognize_using_websocket.rb └── ruby_tasks.sh └── test ├── appveyor_status.rb ├── integration ├── test_assistant_v1.rb ├── test_assistant_v2.rb ├── test_discovery_v1.rb ├── test_discovery_v2.rb ├── test_iam_assistant_v1.rb ├── test_language_translator_v3.rb ├── test_natural_language_understanding_v1.rb ├── test_speech_to_text_v1.rb └── test_text_to_speech_v1.rb ├── test_helper.rb └── unit ├── test_assistant_v1.rb ├── test_assistant_v2.rb ├── test_configure_http_client.rb ├── test_discovery_v1.rb ├── test_discovery_v2.rb ├── test_language_translator_v3.rb ├── test_natural_language_understanding_v1.rb ├── test_speech_to_text_v1.rb └── test_text_to_speech_v1.rb /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 2.1.3 3 | commit = True 4 | message = [skip ci] Bump version: {current_version} -> {new_version} 5 | 6 | [bumpversion:file:lib/ibm_watson/version.rb] 7 | search = {current_version} 8 | replace = {new_version} 9 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mamoonraja1@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | Remember, an issue is not the place to ask questions. If you have issues with the APIs or have a question about the Watson services, see [Stack Overflow](https://stackoverflow.com/questions/tagged/ibm-watson+ruby). 11 | 12 | Before you open an issue, please check if a similar issue already exists or has been closed before. 13 | 14 | **Service Status** 15 | Please review the following: 16 | 17 | - For service issues or 5xx errors, first, go to the [IBM Cloud status page](https://cloud.ibm.com/status?component=compare-comply%2Cdiscovery%2Cconversation%2Cwatson-vision-combined%2Cnatural-language-understanding%2Cnatural-language-classifier%2Clanguage-translator%2Cpersonality-insights%2Cspeech-to-text%2Ctext-to-speech%2Ctone-analyzer&selected=status) and check the status of the service. 18 | - If the service status is OK, continue with a bug report. 19 | 20 | **Describe the bug** 21 | A clear and concise description of what the bug is. 22 | 23 | **To Reproduce** 24 | Steps to reproduce the behavior: 25 | 26 | **Expected behavior** 27 | A clear and concise description of what you expected to happen. 28 | 29 | **Actual behavior** 30 | A clear and concise description of what you expected to happen. 31 | 32 | **Screenshots** 33 | If applicable, add screenshots to help explain your problem. 34 | 35 | **Desktop (please complete the following information):** 36 | - OS: [e.g. iOS] 37 | - Ruby Version 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | Remember, an issue is not the place to ask questions. If you have issues with the APIs or have a question about the Watson services, see [Stack Overflow](https://stackoverflow.com/questions/tagged/ibm-watson+ruby). 11 | 12 | Before you open an issue, please check if a similar issue already exists or has been closed before. 13 | 14 | **Is your feature request related to a problem? Please describe.** 15 | A clear and concise description of what the problem is. 16 | 17 | **Describe the solution you'd like** 18 | A clear and concise description of what you want to happen. 19 | 20 | **Describe alternatives you've considered** 21 | A clear and concise description of any alternative solutions or features you've considered. 22 | 23 | **Additional context** 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has had no 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake 6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby 7 | 8 | name: Build and Test 9 | 10 | on: 11 | push: 12 | branches: [ '**' ] 13 | pull_request: 14 | branches: [ master ] 15 | 16 | # Allows you to run this workflow manually from the Actions tab 17 | workflow_dispatch: 18 | 19 | jobs: 20 | build_test: 21 | name: Build and Test on Ruby ${{ matrix.ruby-version }} and ${{ matrix.os }} 22 | runs-on: ${{ matrix.os }} 23 | strategy: 24 | matrix: 25 | ruby-version: ['2.5', '2.6', '2.7'] 26 | os: [ubuntu-latest] 27 | 28 | steps: 29 | - uses: actions/checkout@v2 30 | - name: Set up Ruby 31 | # change this to (see https://github.com/ruby/setup-ruby#versioning): 32 | uses: ruby/setup-ruby@v1 33 | with: 34 | ruby-version: ${{ matrix.ruby-version }} 35 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 36 | - name: Execute Ruby unit tests with code coverage 37 | if: matrix.ruby-version == '2.6' 38 | env: 39 | COVERAGE: true 40 | run: bundle exec rake test:unit 41 | - name: Execute Ruby unit tests 42 | if: matrix.ruby-version != '2.6' 43 | run: bundle exec rake test:unit 44 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support documentation. 4 | # This workflow will download a prebuilt Ruby version, install dependencies, build and deploy/publish a new release 5 | 6 | name: Deploy and Publish 7 | 8 | on: 9 | workflow_run: 10 | workflows: ["Build and Test"] 11 | branches: [ master ] 12 | types: 13 | - completed 14 | 15 | # Allows you to run this workflow manually from the Action tab 16 | workflow_dispatch: 17 | 18 | jobs: 19 | deploy: 20 | if: "!contains(github.event.head_commit.message, 'skip ci')" 21 | name: Deploy and Publish 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - uses: actions/checkout@v2 26 | with: 27 | persist-credentials: false 28 | 29 | - name: Set up Ruby 2.5 30 | uses: ruby/setup-ruby@v1 31 | with: 32 | ruby-version: 2.5 33 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 34 | 35 | - name: Execute Ruby unit tests 36 | run: bundle exec rake test:unit 37 | 38 | - name: Setup Node.js 39 | uses: actions/setup-node@v1 40 | with: 41 | node-version: 14 42 | 43 | - name: Install Semantic Release dependencies 44 | run: | 45 | sudo apt-get install bumpversion 46 | npm install -g semantic-release 47 | npm install -g @semantic-release/changelog 48 | npm install -g @semantic-release/exec 49 | npm install -g @semantic-release/git 50 | npm install -g @semantic-release/github 51 | npm install -g @semantic-release/commit-analyzer 52 | 53 | - name: Publish to Git Releases and Tags 54 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 57 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 58 | run: npx semantic-release # --dry-run 59 | 60 | - name: Publish to RubyGems 61 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 62 | continue-on-error: true 63 | env: 64 | GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_API_KEY}}" 65 | run: | 66 | mkdir -p $HOME/.gem 67 | touch $HOME/.gem/credentials 68 | chmod 0600 $HOME/.gem/credentials 69 | printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials 70 | gem build *.gemspec 71 | gem push *.gem 72 | 73 | -------------------------------------------------------------------------------- /.github/workflows/integration-test.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support documentation. 4 | # This workflow will download a prebuilt Ruby version, install dependencies and run integration tests with Rake 5 | 6 | name: Run Integration Tests 7 | 8 | # Every Sunday at 8ish PM 9 | on: 10 | schedule: 11 | - cron: "0 20 * * 0" 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | jobs: 17 | integration_test: 18 | name: Build and Run Integration Tests on Ruby ${{ matrix.ruby-version }} and ${{ matrix.os }} 19 | runs-on: ${{ matrix.os }} 20 | strategy: 21 | matrix: 22 | ruby-version: ['2.7'] 23 | os: [ubuntu-latest] 24 | 25 | steps: 26 | - uses: actions/checkout@v2 27 | 28 | - name: Set up Ruby 29 | uses: ruby/setup-ruby@v1 30 | with: 31 | ruby-version: ${{ matrix.ruby-version }} 32 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 33 | 34 | - name: Execute Ruby integration tests 35 | # continue-on-error: true 36 | env: 37 | NATURAL_LANGUAGE_CLASSIFIER_APIKEY: ${{ secrets.NLC_APIKEY }} 38 | NATURAL_LANGUAGE_CLASSIFIER_URL: "https://api.us-south.natural-language-classifier.watson.cloud.ibm.com" 39 | LANGUAGE_TRANSLATOR_APIKEY: ${{ secrets.LT_APIKEY }} 40 | LANGUAGE_TRANSLATOR_URL: "https://api.us-south.language-translator.watson.cloud.ibm.com" 41 | NATURAL_LANGUAGE_UNDERSTANDING_APIKEY: ${{ secrets.NLU_APIKEY }} 42 | NATURAL_LANGUAGE_UNDERSTANDING_URL: "https://api.us-south.natural-language-understanding.watson.cloud.ibm.com" 43 | TONE_ANALYZER_APIKEY: ${{ secrets.TA_APIKEY }} 44 | TONE_ANALYZER_URL: "https://api.us-south.tone-analyzer.watson.cloud.ibm.com" 45 | SPEECH_TO_TEXT_APIKEY: ${{ secrets.STT_APIKEY }} 46 | SPEECH_TO_TEXT_URL: "https://api.us-south.speech-to-text.watson.cloud.ibm.com" 47 | TEXT_TO_SPEECH_APIKEY: ${{ secrets.TTS_APIKEY }} 48 | TEXT_TO_SPEECH_URL: "https://api.us-south.text-to-speech.watson.cloud.ibm.com" 49 | ASSISTANT_APIKEY: ${{ secrets.WA_APIKEY }} 50 | ASSISTANT_WORKSPACE_ID: ${{ secrets.WA_WORKSPACE_ID }} 51 | ASSISTANT_ASSISTANT_ID: ${{ secrets.WA_ASSISTANT_ID }} 52 | ASSISTANT_URL: "https://api.us-south.assistant.watson.cloud.ibm.com" 53 | DISCOVERY_APIKEY: ${{ secrets.D1_APIKEY }} 54 | DISCOVERY_ENVIRONMENT_ID: ${{ secrets.D1_ENVIRONMENT_ID }} 55 | DISCOVERY_COLLECTION_ID: ${{ secrets.D1_COLLECTION_ID }} 56 | DISCOVERY_URL: "https://api.us-south.discovery.watson.cloud.ibm.com" 57 | DISCOVERY_V2_APIKEY: ${{ secrets.D2_APIKEY }} 58 | DISCOVERY_V2_PROJECT_ID: ${{ secrets.D2_PROJECT_ID }} 59 | DISCOVERY_V2_COLLECTION_ID: ${{ secrets.D2_COLLECTION_ID }} 60 | DISCOVERY_V2_URL: "https://api.us-south.discovery.watson.cloud.ibm.com" 61 | run: bundle exec rake test:integration 62 | 63 | - name: Notify slack on success 64 | if: false # success() 65 | env: 66 | SLACK_BOT_TOKEN: ${{ secrets.SLACK_NOTIFICATIONS_BOT_TOKEN }} 67 | uses: voxmedia/github-action-slack-notify-build@v1 68 | with: 69 | channel: watson-e2e-tests 70 | status: SUCCESS 71 | color: good 72 | 73 | - name: Notify slack on failure 74 | if: false # failure() 75 | env: 76 | SLACK_BOT_TOKEN: ${{ secrets.SLACK_NOTIFICATIONS_BOT_TOKEN }} 77 | uses: voxmedia/github-action-slack-notify-build@v1 78 | with: 79 | channel: watson-e2e-tests 80 | status: FAILED 81 | color: danger -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /.idea 5 | /coverage/ 6 | /InstalledFiles 7 | /pkg/ 8 | /spec/reports/ 9 | /spec/examples.txt 10 | /test/tmp/ 11 | /test/version_tmp/ 12 | /tmp/ 13 | .DS_Store 14 | lib/ibm_watson/.swagger-codegen-ignore 15 | lib/ibm_watson/.swagger-codegen 16 | lib/ibm_watson/.openapi-generator-ignore 17 | lib/ibm_watson/.openapi-generator/VERSION 18 | test/html_reports/ 19 | .pre-commit-config.yaml 20 | 21 | # Used by dotenv library to load environment variables. 22 | .env 23 | resources/cnc_input_credentials_file.json 24 | resources/cnc_output_credentials_file.json 25 | 26 | ## Specific to RubyMotion: 27 | .dat* 28 | .repl_history 29 | build/ 30 | *.bridgesupport 31 | build-iPhoneOS/ 32 | build-iPhoneSimulator/ 33 | 34 | ## Specific to RubyMotion (use of CocoaPods): 35 | # 36 | # We recommend against adding the Pods directory to your .gitignore. However 37 | # you should judge for yourself, the pros and cons are mentioned at: 38 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 39 | # 40 | # vendor/Pods/ 41 | 42 | ## Documentation cache and generated files: 43 | /.yardoc/ 44 | /_yardoc/ 45 | /doc/ 46 | /rdoc/ 47 | 48 | ## Environment normalization: 49 | /.bundle/ 50 | /vendor/bundle 51 | /lib/bundler/man/ 52 | 53 | # for a library or gem, you might want to ignore these files since the code is 54 | # intended to run in multiple environments; otherwise, check them in: 55 | Gemfile.lock 56 | # .ruby-version 57 | # .ruby-gemset 58 | 59 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 60 | .rvmrc 61 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "branch": "master", 3 | "debug": "true", 4 | "verifyConditions": ["@semantic-release/git"], 5 | "plugins": [ 6 | "@semantic-release/commit-analyzer", 7 | "@semantic-release/changelog", 8 | [ 9 | "@semantic-release/exec", 10 | { 11 | "prepareCmd": "bumpversion --allow-dirty --current-version ${lastRelease.version} --new-version ${nextRelease.version} patch" 12 | } 13 | ], 14 | [ 15 | "@semantic-release/git", 16 | { 17 | "message": "chore(release): ${nextRelease.version} release notes\n\n${nextRelease.notes}" 18 | } 19 | ], 20 | "@semantic-release/github" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.secrets.baseline: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": { 3 | "files": "^.secrets.baseline$", 4 | "lines": null 5 | }, 6 | "generated_at": "2022-03-22T14:13:54Z", 7 | "plugins_used": [ 8 | { 9 | "name": "AWSKeyDetector" 10 | }, 11 | { 12 | "name": "ArtifactoryDetector" 13 | }, 14 | { 15 | "name": "AzureStorageKeyDetector" 16 | }, 17 | { 18 | "base64_limit": 4.5, 19 | "name": "Base64HighEntropyString" 20 | }, 21 | { 22 | "name": "BasicAuthDetector" 23 | }, 24 | { 25 | "name": "BoxDetector" 26 | }, 27 | { 28 | "name": "CloudantDetector" 29 | }, 30 | { 31 | "ghe_instance": "github.ibm.com", 32 | "name": "GheDetector" 33 | }, 34 | { 35 | "name": "GitHubTokenDetector" 36 | }, 37 | { 38 | "hex_limit": 3, 39 | "name": "HexHighEntropyString" 40 | }, 41 | { 42 | "name": "IbmCloudIamDetector" 43 | }, 44 | { 45 | "name": "IbmCosHmacDetector" 46 | }, 47 | { 48 | "name": "JwtTokenDetector" 49 | }, 50 | { 51 | "keyword_exclude": null, 52 | "name": "KeywordDetector" 53 | }, 54 | { 55 | "name": "MailchimpDetector" 56 | }, 57 | { 58 | "name": "NpmDetector" 59 | }, 60 | { 61 | "name": "PrivateKeyDetector" 62 | }, 63 | { 64 | "name": "SlackDetector" 65 | }, 66 | { 67 | "name": "SoftlayerDetector" 68 | }, 69 | { 70 | "name": "SquareOAuthDetector" 71 | }, 72 | { 73 | "name": "StripeDetector" 74 | }, 75 | { 76 | "name": "TwilioKeyDetector" 77 | } 78 | ], 79 | "results": { 80 | "README.md": [ 81 | { 82 | "hashed_secret": "caccca3d65e2608a75392aeaa0866b0058f4f948", 83 | "is_secret": false, 84 | "is_verified": false, 85 | "line_number": 138, 86 | "type": "Secret Keyword", 87 | "verified_result": null 88 | } 89 | ], 90 | "lib/ibm_watson/speech_to_text_v1.rb": [ 91 | { 92 | "hashed_secret": "76ab55d87544c0b1249f68074227716e6a5488e4", 93 | "is_secret": false, 94 | "is_verified": false, 95 | "line_number": 617, 96 | "type": "Secret Keyword", 97 | "verified_result": null 98 | } 99 | ], 100 | "test/integration/test_discovery_v1.rb": [ 101 | { 102 | "hashed_secret": "12269f85e2defbd83a3a9a5e0675ca66bbdb8080", 103 | "is_secret": false, 104 | "is_verified": false, 105 | "line_number": 207, 106 | "type": "Secret Keyword", 107 | "verified_result": null 108 | } 109 | ], 110 | "test/integration/test_iam_assistant_v1.rb": [ 111 | { 112 | "hashed_secret": "fc13ecfa613c208fa90fa84b744ce26a3b99ee9d", 113 | "is_secret": false, 114 | "is_verified": false, 115 | "line_number": 707, 116 | "type": "Secret Keyword", 117 | "verified_result": null 118 | } 119 | ], 120 | "test/unit/test_language_translator_v3.rb": [ 121 | { 122 | "hashed_secret": "da2f27d2c57a0e1ed2dc3a34b4ef02faf2f7a4c2", 123 | "is_secret": false, 124 | "is_verified": false, 125 | "line_number": 25, 126 | "type": "Hex High Entropy String", 127 | "verified_result": null 128 | }, 129 | { 130 | "hashed_secret": "2308d0fb5ab83a7e92e8000f5f094342d3f87bd0", 131 | "is_secret": false, 132 | "is_verified": false, 133 | "line_number": 634, 134 | "type": "Secret Keyword", 135 | "verified_result": null 136 | }, 137 | { 138 | "hashed_secret": "3255d8449be5e4858e9408cd4ba0498456bd78ba", 139 | "is_secret": false, 140 | "is_verified": false, 141 | "line_number": 646, 142 | "type": "Secret Keyword", 143 | "verified_result": null 144 | } 145 | ] 146 | }, 147 | "version": "0.13.1+ibm.47.dss", 148 | "word_list": { 149 | "file": null, 150 | "hash": null 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Questions 2 | 3 | If you have issues with the APIs or have a question about the Watson services, see [Stack Overflow](https://stackoverflow.com/questions/tagged/ibm-watson+ruby). 4 | 5 | # Code 6 | 7 | * Commits should follow the [Angular commit message guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines). This is because our release tool uses this format for determining release versions and generating changelogs. To make this easier, we recommend using the [Commitizen CLI](https://github.com/commitizen/cz-cli) with the `cz-conventional-changelog` adapter. 8 | 9 | # Issues 10 | 11 | If you encounter an issue with the Ruby library, you are welcome to submit 12 | a [bug report](https://github.com/watson-developer-cloud/ruby-sdk/issues). 13 | Before that, please search for similar issues. It's possible somebody has 14 | already encountered this issue. 15 | 16 | # Pull Requests 17 | 18 | If you want to contribute to the repository, follow these steps: 19 | 20 | 1. Fork the repo. 21 | 2. Install bundler if needed: `gem install bundler` 22 | 3. Install the dependencies: `bundle install` 23 | 4. Make code changes. 24 | 5. Add a test for your changes. Only refactoring and documentation changes require no new tests. 25 | 6. Make the test pass, test your code changes: `bundle exec rake`. 26 | 7. Commit your changes. 27 | 8. Push to your fork and submit a pull request. 28 | 9. Travis-CI and AppVeyor will run the tests for all services once your changes are merged. 29 | 30 | ## Tests 31 | 32 | Ideally, we'd like to see both unit and integration tests on each method. 33 | (Unit tests do not actually connect to the Watson service, integration tests do.) 34 | 35 | Out of the box, `rake` runs integration and unit tests. Put the corresponding credentials in a `.env` file in the root directory for the integration tests to work as intended. 36 | To just run unit or integration tests, run `rake test:unit` or `rake test:integration` 37 | 38 | For the integration tests, tests will only be run for services that have credentials defined in a `.env` file. 39 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | gemspec 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /MIGRATION-V2.md: -------------------------------------------------------------------------------- 1 | ### Ruby SDK V2 Migration guide 2 | 3 | #### Breaking Changes 4 | * The Text To Speech changes listed below 5 | * All services now require a version to be specified (except for stt, tts and nlu) 6 | 7 | #### Service changes 8 | 9 | ##### Assistant v1 10 | 11 | * `list_workspaces()`: `include_count` parameter added 12 | * `list_intents()`: `include_count` parameter added 13 | * `list_examples()`: `include_count` parameter added 14 | * `list_counterexamples()`: `include_count` parameter added 15 | * `list_entities()`: `include_count` parameter added 16 | * `list_values()`: `include_count` parameter added 17 | * `list_synonyms()`: `include_count` parameter added 18 | * `list_dialog_nodes()`: `include_count` parameter added 19 | * `create_workspace()`: reorder `dialog_nodes`, `counterexamples`, `webhooks` parameters 20 | * `update_workspace()`: reorder `dialog_nodes`, `counterexamples`, `webhooks` parameters 21 | * `bulk_classify()`: function added - Identify intents and entities in multiple user utterances. 22 | 23 | ##### Assistant v2 24 | * `bulk_classify()`: function added - Identify intents and entities in multiple user utterances. 25 | 26 | ##### Compare Comply v1 27 | * `list_feedback()`: `before` and `after` parameters removed 28 | 29 | ##### Discovery v2 30 | * `analyze_document()`: function added - Process a document using the specified collection's settings and return it for realtime use. - Currently CP4D only 31 | 32 | ##### Personality Insights V3 33 | * On 1 December 2021, Personality Insights will no longer be available 34 | 35 | ##### Text To Speech V1 36 | * `create_voice_model()`: function changed to `create_custom_model()` 37 | * `list_voice_models()`: function changed to `list_custom_models()` 38 | * `update_voice_model()`: function changed to `update_custom_model()` 39 | * `get_voice_model()`: function changed to `get_custom_model()` 40 | * `delete_voice_model()`: function changed to `delete_custom_model()` 41 | 42 | ##### Visual Recognition V4 43 | * `create_collection()`: `training_status` parameter added 44 | * `update_collection()`: `training_status` parameter added 45 | -------------------------------------------------------------------------------- /MIGRATION-v1.md: -------------------------------------------------------------------------------- 1 | ### Ruby SDK V1 Migration guide 2 | 3 | #### Authentication 4 | 5 | ##### v0.x.x 6 | 7 | Previously different parameters were passed into the service constructor for authentication. 8 | 9 | ```ruby 10 | def example 11 | service = IBMWatson::AssistantV1.new( 12 | iam_apikey: "{iam_apikey}", 13 | url: "{service_endpoint}", 14 | version: "{version_date}" 15 | ); 16 | service.url = "{service_endpoint}"; 17 | end 18 | ``` 19 | 20 | ##### v1.x.x 21 | 22 | Now we use an `Authenticator` to authenticate the service. Available authentication schemes include `IamAuthenticator`, `BasicAuthenticator`, `CloudPakForDataAuthenticator` and `BearerTokenAuthenticator` 23 | 24 | ###### IamAuthenticator 25 | 26 | ```ruby 27 | def example 28 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 29 | apikey: "{apikey}" 30 | ) 31 | service = IBMWatson::AssistantV1.new( 32 | authenticator: authenticator, 33 | version: "{version_date}" 34 | ); 35 | service.service_url = "{serviceUrl}"; 36 | end 37 | ``` 38 | 39 | ##### BasicAuthenticator 40 | 41 | ```ruby 42 | def example 43 | authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 44 | username: "{username}", 45 | password: "{password}" 46 | ) 47 | service = IBMWatson::AssistantV1.new( 48 | authenticator: authenticator, 49 | version: "{version_date}" 50 | ); 51 | service.service_url = "{serviceUrl}"; 52 | end 53 | ``` 54 | 55 | ###### BearerTokenAuthenticator 56 | 57 | ```ruby 58 | authenticator = IBMWatson::Authenticators::BearerTokenAuthenticator.new( 59 | bearer_token: "{bearerToken}" 60 | ) 61 | service = IBMWatson::AssistantV1.new( 62 | authenticator: authenticator, 63 | version: "{version_date}" 64 | ); 65 | service.service_url = "{serviceUrl}"; 66 | ``` 67 | 68 | ###### CloudPakForDataAuthenticator 69 | 70 | ```ruby 71 | authenticator = IBMWatson::Authenticators::CloudPakForDataAuthenticator.new( 72 | url: "https://{cp4d_cluster_host}{:port}", 73 | username: "{username}", 74 | password: "{password}" 75 | ) 76 | service = IBMWatson::AssistantV1.new( 77 | authenticator: authenticator, 78 | version: "{version_date}" 79 | ); 80 | service.service_url = "{serviceUrl}"; 81 | ``` 82 | 83 | #### Supplying credentials 84 | 85 | You can supply credentials to your service using external `ibm-credentials.env` files. 86 | 87 | ```ruby 88 | service = IBMWatson::AssistantV1.new( 89 | version: "{version_date}" 90 | ); 91 | response = service.list_workspaces.result 92 | puts JSON.pretty_generate(response) 93 | ``` 94 | 95 | ##### v0.x.x 96 | 97 | Previously we would look for these files first in the system `home` directory, followed by the current project directory. 98 | 99 | ##### v1.x.x 100 | Now in order to allow developers to have different configurations for each project we look first in the current project directory, followed by the home directory. 101 | 102 | #### Setting the service url 103 | 104 | ##### v0.x.x 105 | 106 | Previously we set the service url by setting url. 107 | 108 | ```ruby 109 | def example 110 | service = IBMWatson::AssistantV1.new( 111 | iam_apikey: "{iam_apikey}", 112 | url: "{service_endpoint}", 113 | version: "{version_date}" 114 | ); 115 | service.url = "{service_endpoint}"; 116 | end 117 | ``` 118 | 119 | ##### v1.x.x 120 | 121 | Now we set the service url by calling the `service_url` setter. 122 | 123 | ```ruby 124 | def example 125 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 126 | apikey: "{apikey}" 127 | ) 128 | service = IBMWatson::AssistantV1.new( 129 | authenticator: authenticator, 130 | version: "{version_date}" 131 | ); 132 | service.service_url = "{serviceUrl}"; 133 | end 134 | ``` 135 | 136 | #### Service changes 137 | 138 | ##### Assistant v1 139 | 140 | * `include_count` is no longer a parameter of the `list_workspaces()` method 141 | * `include_count` is no longer a parameter of the `list_intents()` method 142 | * `include_count` is no longer a parameter of the `list_examples()` method 143 | * `include_count` is no longer a parameter of the `list_counterexamples()` method 144 | * `include_count` is no longer a parameter of the `list_entities()` method 145 | * `include_count` is no longer a parameter of the `list_values()` method 146 | * `include_count` is no longer a parameter of the `list_synonyms()` method 147 | * `include_count` is no longer a parameter of the `list_dialogNodes()` method 148 | * `value_type` was renamed to `type` in the `calue()` method 149 | * `new_value_type` was renamed to `newType` in the `update_value()` method 150 | * `node_type` was renamed to `type` in the `create_dialog_node()` method 151 | * `node_type` was renamed to `type` in the `create_dialog_node()` method 152 | * `new_node_type` was renamed to `new_type` in the `update_dialog_node()` method 153 | 154 | ##### Compare Comply v1 155 | 156 | * `convert_to_html()` method does not require a `filename` parameter 157 | 158 | ##### Discovery v1 159 | 160 | * `return_fields` was renamed to `_return` in the `query()` method 161 | * `logging_optOut` was renamed to `x_watson_logging_optOut` in the `query()` method 162 | * `spelling_suggestions` was added to the `query()` method 163 | * `collection_ids` is no longer a parameter of the `query()` method 164 | * `return_fields` was renamed to `_return` in the `QueryNotices()` method 165 | * `logging_optOut` was renamed to `x_watson_logging_optOut` in the `federated_query()` method 166 | * `collection_ids` is now required in the `federated_query()` method 167 | * `collection_ids` changed position in the `federated_query()` method 168 | * `return_fields` was renamed to `_return` in the `federated_query()` method 169 | * `return_fields` was renamed to `_return` in the `federated_query_notices()` method 170 | * `test_configuration_in_environment()` method was removed 171 | * `query_entities()` method was removed 172 | * `query_relations()` method was removed 173 | 174 | ##### Language Translator v3 175 | 176 | * `default_models` was renamed to `_default` in the `list_models()` method 177 | 178 | ##### Natural Language Classifier v1 179 | 180 | * `metadata` was renamed to `training_metadata` in the `create_classifier()` method 181 | 182 | ##### Speech to Text v1 183 | 184 | * `strict` is no longer a parameter of the `train_acoustic_model()` method 185 | * `recognize_with_websocket()` method was removed 186 | 187 | ##### Visual Recognition v3 188 | 189 | * `detect_faces()` method was removed 190 | 191 | ##### Visual Recognition v4 192 | 193 | * New service! -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | require "ibm_watson" 6 | 7 | # You can add fixtures and/or initialization code here to make experimenting 8 | # with your gem easier. You can also use a different console, if you like. 9 | 10 | # (If you use this, don't forget to add pry to your Gemfile!) 11 | # require "pry" 12 | # Pry.start 13 | 14 | require "irb" 15 | IRB.start(__FILE__) 16 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #Import Ruby base image(change version as needed) 2 | FROM ruby:2.6.3 3 | 4 | #Install Ruby SDK 5 | RUN gem install ibm_watson 6 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | ## Docker 2 | You can use docker to test issues you have with the SDK. 3 | 4 | 1. Install docker 5 | - Mac: 6 | - Windows: 7 | 8 | 2. Download the dockerfile for this SDK and edit as needed. 9 | - Change the ruby version as needed `FROM ruby:` 10 | - For valid ruby base images on docker see 11 | 12 | - Copy code/file that you wish to test into the dockerfile 13 | - Add line `COPY ... ` 14 | 15 | - Set dockerfile to execute code file 16 | - Add line `CMD [ "" ]` 17 | 18 | - For more information on dockerfile construction please visit 19 | 20 | 3. Build and run the docker image. 21 | - Navigate to docker file directory 22 | - To build the docker image run `docker build --tag= .` 23 | - To run the docker image run `docker run ` 24 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Examples 2 | This example shows you how to use the Ruby SDK. -------------------------------------------------------------------------------- /examples/assistant_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/assistant_v1" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | assistant = IBMWatson::AssistantV1.new( 19 | version: "2018-02-16", 20 | authenticator: authenticator 21 | ) 22 | assistant.service_url = "{service_url}" 23 | 24 | ######################### 25 | # Workspaces 26 | ######################### 27 | 28 | create_workspace_data = { 29 | "name" => "test_workspace", 30 | "description" => "integration tests", 31 | "language" => "en", 32 | "intents" => [ 33 | { 34 | "intent" => "hello", 35 | "description" => "string", 36 | "examples" => [ 37 | { 38 | "text" => "good morning" 39 | } 40 | ] 41 | } 42 | ], 43 | "entities" => [ 44 | { 45 | "entity" => "pizza_toppings", 46 | "description" => "Tasty pizza toppings", 47 | "metadata" => { 48 | "property" => "value" 49 | } 50 | } 51 | ], 52 | "counterexamples" => [ 53 | { 54 | "text" => "string" 55 | } 56 | ], 57 | "metadata" => {} 58 | } 59 | 60 | response = assistant.create_workspace( 61 | name: create_workspace_data["name"], 62 | description: create_workspace_data["description"], 63 | language: "en", 64 | intents: create_workspace_data["intents"], 65 | entities: create_workspace_data["entities"], 66 | counterexamples: create_workspace_data["counterexamples"], 67 | metadata: create_workspace_data["metadata"] 68 | ).result 69 | puts JSON.pretty_generate(response) 70 | 71 | workspace_id = response["workspace_id"] 72 | p "Workspace id #{workspace_id}" 73 | 74 | response = assistant.get_workspace( 75 | workspace_id: workspace_id, 76 | export: true 77 | ).result 78 | puts JSON.pretty_generate(response) 79 | 80 | # message 81 | response = assistant.message( 82 | workspace_id: workspace_id, 83 | input: { 84 | "text" => "What's the weather like?" 85 | }, 86 | context: { 87 | "metadata" => { 88 | "deployment" => "myDeployment" 89 | } 90 | } 91 | ).result 92 | puts JSON.pretty_generate(response) 93 | 94 | response = assistant.list_workspaces.result 95 | puts JSON.pretty_generate(response) 96 | 97 | response = assistant.update_workspace( 98 | workspace_id: workspace_id, 99 | description: "Updated test workspace." 100 | ).result 101 | puts JSON.pretty_generate(response) 102 | 103 | # see cleanup section below for delete_workspace example 104 | 105 | ######################### 106 | # Intents 107 | ######################### 108 | 109 | examples = [{ "text" => "good morning" }] 110 | response = assistant.create_intent( 111 | workspace_id: workspace_id, 112 | intent: "test_intent", 113 | description: "Test intent.", 114 | examples: examples 115 | ).result 116 | puts JSON.pretty_generate(response) 117 | 118 | response = assistant.get_intent( 119 | workspace_id: workspace_id, 120 | intent: "test_intent", 121 | export: true 122 | ).result 123 | puts JSON.pretty_generate(response) 124 | 125 | response = assistant.list_intents( 126 | workspace_id: workspace_id, 127 | export: true 128 | ).result 129 | puts JSON.pretty_generate(response) 130 | 131 | response = assistant.update_intent( 132 | workspace_id: workspace_id, 133 | intent: "test_intent", 134 | new_intent: "updated_test_intent", 135 | new_description: "Updated test intent." 136 | ).result 137 | puts JSON.pretty_generate(response) 138 | 139 | # see cleanup section below for delete_intent example 140 | 141 | ######################### 142 | # Examples 143 | ######################### 144 | 145 | response = assistant.create_example( 146 | workspace_id: workspace_id, 147 | intent: "updated_test_intent", 148 | text: "Gimme a pizza with pepperoni" 149 | ).result 150 | puts JSON.pretty_generate(response) 151 | 152 | response = assistant.get_example( 153 | workspace_id: workspace_id, 154 | intent: "updated_test_intent", 155 | text: "Gimme a pizza with pepperoni" 156 | ).result 157 | puts JSON.pretty_generate(response) 158 | 159 | response = assistant.list_examples( 160 | workspace_id: workspace_id, 161 | intent: "updated_test_intent" 162 | ).result 163 | puts JSON.pretty_generate(response) 164 | 165 | response = assistant.update_example( 166 | workspace_id: workspace_id, 167 | intent: "updated_test_intent", 168 | text: "Gimme a pizza with pepperoni", 169 | new_text: "Gimme a pizza with pepperoni" 170 | ).result 171 | puts JSON.pretty_generate(response) 172 | 173 | response = assistant.delete_example( 174 | workspace_id: workspace_id, 175 | intent: "updated_test_intent", 176 | text: "Gimme a pizza with pepperoni" 177 | ).result 178 | puts JSON.pretty_generate(response) 179 | 180 | ######################### 181 | # Counter Examples 182 | ######################### 183 | 184 | response = assistant.create_counterexample( 185 | workspace_id: workspace_id, 186 | text: "I want financial advice today." 187 | ).result 188 | puts JSON.pretty_generate(response) 189 | 190 | response = assistant.get_counterexample( 191 | workspace_id: workspace_id, 192 | text: "I want financial advice today." 193 | ).result 194 | puts JSON.pretty_generate(response) 195 | 196 | response = assistant.list_counterexamples(workspace_id: workspace_id).result 197 | puts JSON.pretty_generate(response) 198 | 199 | response = assistant.update_counterexample( 200 | workspace_id: workspace_id, 201 | text: "I want financial advice today.", 202 | new_text: "I want financial advice today." 203 | ).result 204 | puts JSON.pretty_generate(response) 205 | 206 | response = assistant.delete_counterexample( 207 | workspace_id: workspace_id, 208 | text: "I want financial advice today." 209 | ).result 210 | puts JSON.pretty_generate(response) 211 | 212 | ######################### 213 | # Entities 214 | ######################### 215 | 216 | values = [{ "value" => "juice" }] 217 | response = assistant.create_entity( 218 | workspace_id: workspace_id, 219 | entity: "test_entity", 220 | description: "A test entity.", 221 | values: values 222 | ).result 223 | puts JSON.pretty_generate(response) 224 | 225 | entities = [ 226 | { 227 | "entity" => "pattern_entity", 228 | "values" => [ 229 | { 230 | "value" => "value0", 231 | "patterns" => ["\\d{6}\\w{1}\\d{7}"], 232 | "value_type" => "patterns" 233 | }, 234 | { 235 | "value" => "value1", 236 | "patterns" => ["[-9][0-9][0-9][0-9][0-9]~! [1-9][1-9][1-9][1-9][1-9][1-9]"], 237 | "value_type" => "patterns" 238 | }, 239 | { 240 | "value" => "value2", 241 | "patterns" => ["[a-z-9]{17}"], 242 | "value_type" => "patterns" 243 | }, 244 | { 245 | "value" => "value3", 246 | "patterns" => [ 247 | "\\d{3}(\\ |-)\\d{3}(\\ |-)\\d{4}", 248 | "\\(\\d{3}\\)(\\ |-)\\d{3}(\\ |-)\\d{4}" 249 | ], 250 | "value_type" => "patterns" 251 | }, 252 | { 253 | "value" => "value4", 254 | "patterns" => ["\\b\\d{5}\\b"], 255 | "value_type" => "patterns" 256 | } 257 | ] 258 | } 259 | ] 260 | response = assistant.create_entity( 261 | workspace_id: workspace_id, 262 | entity: entities[0]["entity"], 263 | values: entities[0]["values"] 264 | ).result 265 | puts JSON.pretty_generate(response) 266 | 267 | response = assistant.get_entity( 268 | workspace_id: workspace_id, 269 | entity: entities[0]["entity"], 270 | export: true 271 | ).result 272 | puts JSON.pretty_generate(response) 273 | 274 | response = assistant.list_entities(workspace_id: workspace_id).result 275 | puts JSON.pretty_generate(response) 276 | 277 | response = assistant.update_entity( 278 | workspace_id: workspace_id, 279 | entity: "test_entity", 280 | new_description: "An updated test entity." 281 | ).result 282 | puts JSON.pretty_generate(response) 283 | 284 | response = assistant.delete_entity( 285 | workspace_id: workspace_id, 286 | entity: "test_entity" 287 | ).result 288 | puts JSON.pretty_generate(response) 289 | 290 | ######################### 291 | # Synonyms 292 | ######################### 293 | 294 | values = [{ "value" => "orange juice" }] 295 | assistant.create_entity( 296 | workspace_id: workspace_id, 297 | entity: "beverage", 298 | values: values 299 | ) 300 | 301 | response = assistant.create_synonym( 302 | workspace_id: workspace_id, 303 | entity: "beverage", 304 | value: "orange juice", 305 | synonym: "oj" 306 | ).result 307 | puts JSON.pretty_generate(response) 308 | 309 | response = assistant.get_synonym( 310 | workspace_id: workspace_id, 311 | entity: "beverage", 312 | value: "orange juice", 313 | synonym: "oj" 314 | ).result 315 | puts JSON.pretty_generate(response) 316 | 317 | response = assistant.list_synonyms( 318 | workspace_id: workspace_id, 319 | entity: "beverage", 320 | value: "orange juice" 321 | ).result 322 | puts JSON.pretty_generate(response) 323 | 324 | response = assistant.update_synonym( 325 | workspace_id: workspace_id, 326 | entity: "beverage", 327 | value: "orange juice", 328 | synonym: "oj", 329 | new_synonym: "OJ" 330 | ).result 331 | puts JSON.pretty_generate(response) 332 | 333 | response = assistant.delete_synonym( 334 | workspace_id: workspace_id, 335 | entity: "beverage", 336 | value: "orange juice", 337 | synonym: "OJ" 338 | ).result 339 | puts JSON.pretty_generate(response) 340 | 341 | assistant.delete_entity(workspace_id: workspace_id, entity: "beverage") 342 | 343 | ######################### 344 | # Values 345 | ######################### 346 | 347 | assistant.create_entity(workspace_id: workspace_id, entity: "test_entity") 348 | 349 | response = assistant.create_value( 350 | workspace_id: workspace_id, 351 | entity: "test_entity", 352 | value: "test" 353 | ).result 354 | puts JSON.pretty_generate(response) 355 | 356 | response = assistant.get_value( 357 | workspace_id: workspace_id, 358 | entity: "test_entity", 359 | value: "test" 360 | ).result 361 | puts JSON.pretty_generate(response) 362 | 363 | response = assistant.list_values( 364 | workspace_id: workspace_id, 365 | entity: "test_entity" 366 | ).result 367 | puts JSON.pretty_generate(response) 368 | 369 | response = assistant.update_value( 370 | workspace_id: workspace_id, 371 | entity: "test_entity", 372 | value: "test", 373 | new_value: "example" 374 | ).result 375 | puts JSON.pretty_generate(response) 376 | 377 | response = assistant.delete_value( 378 | workspace_id: workspace_id, 379 | entity: "test_entity", 380 | value: "example" 381 | ).result 382 | puts JSON.pretty_generate(response) 383 | 384 | assistant.delete_entity(workspace_id: workspace_id, entity: "test_entity") 385 | 386 | ######################### 387 | # Dialog nodes 388 | ######################### 389 | create_dialog_node = { 390 | "dialog_node" => "greeting", 391 | "description" => "greeting messages", 392 | "actions" => [ 393 | { 394 | "name" => "hello", 395 | "type" => "client", 396 | "parameters" => {}, 397 | "result_variable" => "string", 398 | "credentials" => "string" 399 | } 400 | ] 401 | } 402 | response = assistant.create_dialog_node( 403 | workspace_id: workspace_id, 404 | dialog_node: create_dialog_node["dialog_node"], 405 | description: create_dialog_node["description"], 406 | actions: create_dialog_node["actions"] 407 | ).result 408 | puts JSON.pretty_generate(response) 409 | 410 | response = assistant.get_dialog_node( 411 | workspace_id: workspace_id, 412 | dialog_node: create_dialog_node["dialog_node"] 413 | ).result 414 | puts JSON.pretty_generate(response) 415 | 416 | response = assistant.list_dialog_nodes(workspace_id: workspace_id).result 417 | puts JSON.pretty_generate(response) 418 | 419 | response = assistant.update_dialog_node( 420 | workspace_id: workspace_id, 421 | dialog_node: create_dialog_node["dialog_node"], 422 | new_dialog_node: "updated_node" 423 | ).result 424 | puts JSON.pretty_generate(response) 425 | 426 | response = assistant.delete_dialog_node(workspace_id: workspace_id, dialog_node: "updated_node").result 427 | puts JSON.pretty_generate(response) 428 | 429 | ######################### 430 | # Logs 431 | ######################### 432 | 433 | response = assistant.list_logs(workspace_id: workspace_id).result 434 | puts JSON.pretty_generate(response) 435 | 436 | ######################### 437 | # Clean-up 438 | ######################### 439 | 440 | response = assistant.delete_intent( 441 | workspace_id: workspace_id, 442 | intent: "updated_test_intent" 443 | ).result 444 | puts JSON.pretty_generate(response) 445 | 446 | response = assistant.delete_workspace(workspace_id: workspace_id).result 447 | puts JSON.pretty_generate(response) 448 | -------------------------------------------------------------------------------- /examples/assistant_v2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/assistant_v2" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | # If you have username & password in your credentials use: 19 | service = IBMWatson::AssistantV2.new( 20 | authenticator: authenticator, 21 | version: "2018-09-17" 22 | ) 23 | service.service_url = "{service_url}" 24 | 25 | ######################### 26 | # Sessions 27 | ######################### 28 | response = service.create_session( 29 | assistant_id: "assistant_id" 30 | ) 31 | 32 | puts JSON.pretty_generate(response.result) 33 | 34 | session_id = response.result["session_id"] 35 | service.delete_session( 36 | assistant_id: "assistant_id", 37 | session_id: session_id 38 | ) 39 | 40 | ######################### 41 | # Message 42 | ######################### 43 | response = service.message( 44 | assistant_id: "assistant_id", 45 | session_id: "session_id", 46 | input: { "text" => "Turn on the lights" }, 47 | context: nil 48 | ) 49 | puts JSON.pretty_generate(response.result) 50 | -------------------------------------------------------------------------------- /examples/compare_comply_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/compare_comply_v1" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | compare_comply = IBMWatson::CompareComplyV1.new( 19 | version: "2019-09-16", 20 | authenticator: authenticator 21 | ) 22 | compare_comply.service_url = "{service_url}" 23 | 24 | puts JSON.pretty_generate(compare_comply.list_feedback.result) 25 | -------------------------------------------------------------------------------- /examples/discovery_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/discovery_v1" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | discovery = IBMWatson::DiscoveryV1.new( 19 | version: "2019-04-30", 20 | authenticator: authenticator 21 | ) 22 | discovery.service_url = "{service_url}" 23 | 24 | environments = discovery.list_environments.result 25 | puts JSON.pretty_generate(environments) 26 | 27 | news_environment_id = "system" 28 | 29 | collections = discovery.list_collections( 30 | environment_id: news_environment_id 31 | ).result 32 | news_collections = collections["collections"] 33 | puts JSON.pretty_generate(collections) 34 | 35 | configurations = discovery.list_configurations( 36 | environment_id: news_environment_id 37 | ).result 38 | puts JSON.pretty_generate(configurations) 39 | 40 | query_results = discovery.query( 41 | environment_id: news_environment_id, 42 | collection_id: news_collections[0]["collection_id"], 43 | filter: "extracted_metadata.sha1::f5*", 44 | return_fields: "extracted_metadata.sha1" 45 | ).result 46 | puts JSON.pretty_generate(query_results) 47 | 48 | # new_environment = discovery.create_environment( 49 | # name: "new env", 50 | # description: "bogus env" 51 | # ).result 52 | # puts JSON.pretty_generate(new_environment) 53 | 54 | # if discovery.get_environment(environment_id: new_environment["environment_id"]).result["status"] == "active" 55 | # writable_environment_id = new_environment["environment_id"] 56 | # new_collection = discovery.create_collection( 57 | # environment_id: writable_environment_id, 58 | # name: "Example Collection", 59 | # description: "just a test" 60 | # ).result 61 | 62 | # puts JSON.pretty_generate(new_collection) 63 | # puts JSON.pretty_generate(discovery.get_collections(environment_id: writable_environment_id).result) 64 | # res = discovery.delete_collection( 65 | # environment_id: "10b733d0-1232-4924-a670-e6ffaed2e641", 66 | # collection_id: new_collection["collection_id"] 67 | # ).result 68 | # puts JSON.pretty_generate(res) 69 | # end 70 | 71 | # collections = discovery.list_collections( 72 | # environment_id: writable_environment_id 73 | # ).result 74 | # puts JSON.pretty_generate(collections) 75 | 76 | # File.open(Dir.getwd + "/resources/simple.html") do |file_info| 77 | # puts JSON.pretty_generate(discovery.test_document(environment_id: writable_environment_id, file: file_info).result) 78 | # end 79 | 80 | # File.open(Dir.getwd + "/resources/simple.html") do |file_info| 81 | # res = discovery.add_document( 82 | # environment_id: writable_environment_id, 83 | # collection_id: collections["collections"][0]["collection_id"], 84 | # file: file_info 85 | # ).result 86 | # puts JSON.pretty_generate(res) 87 | # end 88 | 89 | # res = discovery.get_collection( 90 | # environment_id: writable_environment_id, 91 | # collection_id: collections["collections"][0]["collection_id"] 92 | # ).result 93 | # puts JSON.pretty_generate(res) 94 | 95 | # res = discovery.delete_environment( 96 | # environment_id: writable_environment_id 97 | # ).result 98 | # puts JSON.pretty_generate(res) 99 | -------------------------------------------------------------------------------- /examples/discovery_v2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/discovery_v2" 6 | 7 | ## Important: Discovery v2 is only available on Cloud Pak for Data. ## 8 | 9 | ## Authentication ## 10 | ## Option 1: username/password 11 | # authenticator = IBMWatson::Authenticators::CloudPakForDataAuthenticator.new( 12 | # username: "{username}", 13 | # password: "{password}", 14 | # url: "{authentication_url}", 15 | # disable_ssl: true 16 | # ) 17 | 18 | ## Option 2: bearer token 19 | authenticator = IBMWatson::Authenticators::BearerTokenAuthenticator.new( 20 | bearer_token: "{token}" 21 | ) 22 | 23 | discovery = IBMWatson::DiscoveryV2.new( 24 | authenticator: authenticator, 25 | version: "2019-11-21" 26 | ) 27 | discovery.service_url = "{service_url}" 28 | discovery.configure_http_client(disable_ssl_verification: true) 29 | 30 | collections = discovery.list_collections( 31 | project_id: "{project_id}" 32 | ).result 33 | 34 | puts JSON.pretty_generate(collections) 35 | 36 | query_response = discovery.query( 37 | project_id: "{project_id}", 38 | count: 10 39 | ).result 40 | puts JSON.pretty_generate(query_response) 41 | 42 | autocomplete_response = discovery.get_autocompletion( 43 | project_id: "{project_id}", 44 | prefix: "hi how are " 45 | ) 46 | puts JSON.pretty_generate(autocomplete_response) 47 | -------------------------------------------------------------------------------- /examples/language_translator_v3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/language_translator_v3" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | language_translator = IBMWatson::LanguageTranslatorV3.new( 19 | version: "2018-05-31", 20 | authenticator: authenticator 21 | ) 22 | language_translator.service_url = "{service_url}" 23 | 24 | ## Translate 25 | translation = language_translator.translate( 26 | text: "Hello", 27 | model_id: "en-es" 28 | ).result 29 | puts JSON.pretty_generate(translation) 30 | 31 | ## List identifiable languages 32 | # languages = language_translator.list_identifiable_languages.result 33 | # puts JSON.pretty_generate(languages) 34 | 35 | ## Identify 36 | # language = language_translator.identify( 37 | # text: "Language translator translates text from one language to another" 38 | # ).result 39 | # puts JSON.pretty_generate(language) 40 | 41 | ## List models 42 | # models = language_translator.list_models( 43 | # source: "en" 44 | # ).result 45 | # puts JSON.pretty_generate(models) 46 | 47 | ## Create model 48 | # glossary = File.open(Dir.getwd + "/resources/glossary.tmx") 49 | # response = language_translator.create_model( 50 | # base_model_id: "en-es", 51 | # name: "custom-english-to-spanish", 52 | # forced_glossary: glossary 53 | # ).result 54 | # puts JSON.pretty_generate(response) 55 | 56 | ## Delete model 57 | # puts JSON.pretty_generate(language_translator.delete_model(model_id: "9f8d9c6f-2123-462f-9793-f17fdcb77cd6").result) 58 | 59 | ## Get model details 60 | # model = language_translator.get_model(model_id: "fdadfc3b-0b96-4276-a6e5-f5c4a29711fc").result 61 | # puts JSON.pretty_generate(model) 62 | 63 | ## Document translation 64 | # list documents 65 | document_list = language_translator.list_documents 66 | puts JSON.pretty_generate(document_list.result) 67 | 68 | # translate document 69 | file = File.open(Dir.getwd + "translation_doc.txt") 70 | document_status = language_translator.translate_document( 71 | file: file 72 | ) 73 | puts JSON.pretty_generate(document_status.result) 74 | 75 | # get document status 76 | document_status = language_translator.get_document_status( 77 | document_id: "1bdb9528-bf73-45eb-87fa-c4f519af23a0" 78 | ) 79 | puts JSON.pretty_generate(document_status) 80 | 81 | # delete document 82 | language_translator.delete_document( 83 | document_id: "1bdb9528-bf73-45eb-87fa-c4f519af23a0" 84 | ) 85 | 86 | # get translated document 87 | translated_document = language_translator.get_translated_document( 88 | document_id: "1bdb9528-bf73-45eb-87fa-c4f519af23a0" 89 | ) 90 | puts JSON.pretty_generate(translated_document.result) 91 | -------------------------------------------------------------------------------- /examples/natural_language_classifier_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/natural_language_classifier_v1" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | natural_language_classifier = IBMWatson::NaturalLanguageClassifierV1.new( 19 | authenticator: authenticator 20 | ) 21 | natural_language_classifier.service_url = "{service_url}" 22 | 23 | classifiers = natural_language_classifier.list_classifiers.result 24 | puts JSON.pretty_generate(classifiers) 25 | 26 | # create a classifier 27 | training_data = File.open(Dir.getwd + "/resources/weather_data_train.csv") 28 | metadata = { 29 | "name" => "my-classifier", 30 | "language" => "en" 31 | } 32 | classifier = natural_language_classifier.create_classifier( 33 | metadata: metadata, 34 | training_data: training_data 35 | ).result 36 | classifier_id = classifier["classifier_id"] 37 | puts JSON.pretty_generate(classifier) 38 | 39 | status = natural_language_classifier.get_classifier( 40 | classifier_id: classifier_id 41 | ).result 42 | puts JSON.pretty_generate(status) 43 | 44 | if status["status"] == "Available" 45 | classes = natural_language_classifier.classify( 46 | classifier_id: classifier_id, 47 | text: "How hot will it be tomorrow?" 48 | ).result 49 | puts JSON.pretty_generate(classes) 50 | end 51 | 52 | if status["status"] == "Available" 53 | collection = [{ "text" => "How hot will it be today?" }, { "text" => "Is it hot outside?" }] 54 | classes = natural_language_classifier.classify_collection( 55 | classifier_id: classifier_id, 56 | collection: collection 57 | ).result 58 | puts JSON.pretty_generate(classes) 59 | end 60 | 61 | delete = natural_language_classifier.delete_classifier(classifier_id: classifier_id).result 62 | puts JSON.pretty_generate(delete) 63 | -------------------------------------------------------------------------------- /examples/natural_language_understanding_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/natural_language_understanding_v1" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | natural_language_understanding = IBMWatson::NaturalLanguageUnderstandingV1.new( 19 | authenticator: authenticator, 20 | version: "2018-03-16" 21 | ) 22 | natural_language_understanding.service_url = "{service_url}" 23 | 24 | response = natural_language_understanding.analyze( 25 | text: "Bruce Banner is the Hulk and Bruce Wayne is BATMAN! " \ 26 | "Superman fears not Banner, but Wayne", 27 | features: { 28 | "entities" => {}, 29 | "keywords" => {} 30 | } 31 | ).result 32 | puts JSON.pretty_generate(response) 33 | -------------------------------------------------------------------------------- /examples/personality_insights_v3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "ibm_watson/personality_insights_v3" 4 | require "ibm_watson/authenticators" 5 | require "json" 6 | 7 | # The example returns a JSON response whose content is the same as that in 8 | # ../resources/personality-v3-expect2.txt 9 | 10 | # If using IAM 11 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 12 | apikey: "{iam_api_key}" 13 | ) 14 | 15 | # If you have username & password in your credentials use: 16 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 17 | # username: "{username}", 18 | # password: "{password}" 19 | # ) 20 | 21 | personality_insights = IBMWatson::PersonalityInsightsV3.new( 22 | authenticator: authenticator, 23 | version: "2017-10-13" 24 | ) 25 | personality_insights.service_url = "{service_url}" 26 | 27 | profile = nil 28 | File.open(Dir.getwd + "/resources/personality-v3.json") do |profile_json| 29 | profile = personality_insights.profile( 30 | accept: "application/json", 31 | content: profile_json, 32 | content_type: "application/json", 33 | raw_scores: true, 34 | consumption_preferences: true 35 | ).result 36 | end 37 | puts JSON.pretty_generate(profile) 38 | -------------------------------------------------------------------------------- /examples/speech_to_text_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "ibm_watson/speech_to_text_v1" 4 | require "ibm_watson/websocket/recognize_callback" 5 | require "ibm_watson/authenticators" 6 | require "json" 7 | 8 | # If using IAM 9 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 10 | apikey: "{iam_api_key}" 11 | ) 12 | 13 | # If you have username & password in your credentials use: 14 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 15 | # username: "{username}", 16 | # password: "{password}" 17 | # ) 18 | 19 | speech_to_text = IBMWatson::SpeechToTextV1.new( 20 | authenticator: authenticator 21 | ) 22 | speech_to_text.service_url = "{service_url}" 23 | 24 | puts JSON.pretty_generate(speech_to_text.list_models.result) 25 | 26 | puts JSON.pretty_generate(speech_to_text.get_model(model_id: "en-US_BroadbandModel").result) 27 | 28 | File.open(Dir.getwd + "/resources/speech.wav") do |audio_file| 29 | recognition = speech_to_text.recognize( 30 | audio: audio_file, 31 | content_type: "audio/wav", 32 | timestamps: true, 33 | word_confidence: true 34 | ).result 35 | puts JSON.pretty_generate(recognition) 36 | end 37 | 38 | # Example using websockets 39 | class MyRecognizeCallback < IBMWatson::RecognizeCallback 40 | def initialize 41 | super 42 | end 43 | 44 | def on_transcription(transcript:) 45 | puts JSON.pretty_generate(transcript) 46 | end 47 | 48 | def on_connected 49 | puts "Connection was successful" 50 | end 51 | 52 | def on_error(error:) 53 | puts "Error received: #{error}" 54 | end 55 | 56 | def on_inactivity_timeout(error:) 57 | puts "Inactivity timeout: #{error}" 58 | end 59 | 60 | def on_listening 61 | puts "Service is listening" 62 | end 63 | 64 | def on_transcription_complete 65 | puts "Transcription completed" 66 | end 67 | 68 | def on_hypothesis(hypothesis:) 69 | puts hypothesis.to_s 70 | end 71 | 72 | def on_data(data:) 73 | puts data.to_s 74 | end 75 | end 76 | 77 | mycallback = MyRecognizeCallback.new 78 | File.open(Dir.getwd + "/resources/speech.wav") do |audio_file| 79 | speech_to_text.recognize_using_websocket( 80 | audio: audio_file, 81 | recognize_callback: mycallback, 82 | content_type: "audio/wav" 83 | ).start 84 | end 85 | 86 | # Example using websockets and a pseudo audio stream 87 | # The websocket method has the ability to accept audio in chunks 88 | # This example uses chunks of an audio file to simulate an audio stream, such as a microphone 89 | speech = speech_to_text.recognize_using_websocket( 90 | chunk_data: true, # Tell the websocket object that audio will be given in chunks 91 | recognize_callback: mycallback, 92 | interim_results: true, 93 | inactivity_timeout: 3, 94 | content_type: "audio/wav" 95 | ) 96 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 97 | Thread.new do 98 | until audio_file.eof? 99 | chunk = audio_file.read(1024) 100 | speech.add_audio_chunk(chunk: chunk) 101 | end 102 | sleep(1) 103 | speech.stop_audio # Tell the websocket object that no more audio will be added 104 | end 105 | thr = Thread.new { speech.start } 106 | thr.join 107 | 108 | # Example using websockets using multiple threads for two audio files 109 | # Make sure you create two wrappers of service and then start the threads 110 | speech = speech_to_text.recognize_using_websocket( 111 | audio: File.open(Dir.getwd + "/resources/speech.wav"), 112 | recognize_callback: MyRecognizeCallback.new, 113 | interim_results: true, 114 | timestamps: true, 115 | max_alternatives: 2, 116 | word_alternatives_threshold: 0.5, 117 | content_type: "audio/wav" 118 | ) 119 | 120 | speech_with_pause = speech_to_text.recognize_using_websocket( 121 | audio: File.open(Dir.getwd + "/resources/sound-with-pause.wav"), 122 | recognize_callback: MyRecognizeCallback.new, 123 | interim_results: true, 124 | timestamps: true, 125 | max_alternatives: 2, 126 | word_alternatives_threshold: 0.5, 127 | content_type: "audio/wav" 128 | ) 129 | 130 | main_thread = Thread.new { speech.start } 131 | another_thread = Thread.new { speech_with_pause.start } 132 | 133 | main_thread.join 134 | another_thread.join 135 | -------------------------------------------------------------------------------- /examples/text_to_speech_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/text_to_speech_v1" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | # If you have username & password in your credentials use: 19 | text_to_speech = IBMWatson::TextToSpeechV1.new( 20 | authenticator: authenticator 21 | ) 22 | text_to_speech.service_url = "{service_url}" 23 | 24 | puts JSON.pretty_generate(text_to_speech.list_voices.result) 25 | 26 | File.new("output.wav", "w+") do |audio_file| 27 | response = text_to_speech.synthesize( 28 | text: "Hello world!", 29 | accept: "audio/wav", 30 | voice: "en-US_AllisonVoice" 31 | ).result 32 | audio_file << response 33 | end 34 | 35 | # puts JSON.pretty_generate(text_to_speech.get_pronunciation(text: "Watson", format: "spr").result) 36 | 37 | # puts JSON.pretty_generate(text_to_speech.list_voice_models.result) 38 | 39 | # puts JSON.pretty_generate(text_to_speech.create_voice_model(name: "test-customization").result) 40 | 41 | # puts JSON.pretty_generate(text_to_speech.update_voice_model(customization_id: "YOUR CUSTOMIZATION ID", name: "new name").result) 42 | 43 | # puts JSON.pretty_generate(text_to_speech.get_voice_model(customization_id: "YOUR CUSTOMIZATION ID").result) 44 | 45 | # puts JSON.pretty_generate(text_to_speech.list_words(customization_id: "YOUR CUSTOMIZATION ID").result) 46 | 47 | # puts JSON.pretty_generate(text_to_speech.add_words( # rubocop:disable Style/AsciiComments 48 | # customization_id: "YOUR CUSTOMIZATION ID", 49 | # words: [ 50 | # { 51 | # "word" => "resume", 52 | # "translation" => "rɛzʊmeɪ" 53 | # } 54 | # ] 55 | # ).result) 56 | 57 | # puts JSON.pretty_generate(text_to_speech.add_word( 58 | # customization_id: "YOUR CUSTOMIZATION ID", 59 | # word: "resume", 60 | # translation: "rɛzʊmeɪ" 61 | # ).result) # rubocop:enable Style/AsciiComments 62 | 63 | # puts JSON.pretty_generate(text_to_speech.get_word(customization_id: "YOUR CUSTOMIZATION ID", word: "resume").result) 64 | 65 | # puts JSON.pretty_generate(text_to_speech.delete_word(customization_id: "YOUR CUSTOMIZATION ID", word: "resume")) 66 | 67 | # puts JSON.pretty_generate(text_to_speech.delete_voice_model(customization_id: "YOUR CUSTOMIZATION ID")) 68 | -------------------------------------------------------------------------------- /examples/tone_analyzer_v3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/tone_analyzer_v3" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | tone_analyzer = IBMWatson::ToneAnalyzerV3.new( 19 | authenticator: authenticator, 20 | version: "2017-09-21" 21 | ) 22 | tone_analyzer.service_url = "{service_url}" 23 | 24 | utterances = [ 25 | { 26 | "text" => "I am very happy.", 27 | "user" => "glenn" 28 | }, 29 | { 30 | "text" => "It is a good day.", 31 | "user" => "glenn" 32 | } 33 | ] 34 | p "\ntone_chat example 1:\n" 35 | puts JSON.pretty_generate(tone_analyzer.tone_chat(utterances: utterances).result) 36 | 37 | p "\ntone example 1:\n" 38 | puts JSON.pretty_generate(tone_analyzer.tone( 39 | tone_input: "I am very happy. It is a good day.", 40 | content_type: "text/plain" 41 | ).result) 42 | 43 | p "\ntone example 2:\n" 44 | File.open(Dir.getwd + "/resources/tone-example.json") do |tone_json| 45 | tone = tone_analyzer.tone( 46 | tone_input: JSON.parse(tone_json.read)["text"], 47 | content_type: "text/plain" 48 | ).result 49 | puts JSON.pretty_generate(tone) 50 | end 51 | 52 | p "\ntone example 3:\n" 53 | File.open(Dir.getwd + "/resources/tone-example.json") do |tone_json| 54 | tone = tone_analyzer.tone( 55 | tone_input: JSON.parse(tone_json.read)["text"], 56 | content_type: "text/plain", 57 | sentences: true 58 | ).result 59 | puts JSON.pretty_generate(tone) 60 | end 61 | 62 | p "\ntone example 4:\n" 63 | File.open(Dir.getwd + "/resources/tone-example.json") do |tone_json| 64 | tone = tone_analyzer.tone( 65 | tone_input: JSON.parse(tone_json.read), 66 | content_type: "application/json" 67 | ).result 68 | puts JSON.pretty_generate(tone) 69 | end 70 | 71 | p "\ntone example 5:\n" 72 | File.open(Dir.getwd + "/resources/tone-example-html.json") do |tone_html| 73 | tone = tone_analyzer.tone( 74 | tone_input: JSON.parse(tone_html.read)["text"], 75 | content_type: "text/html" 76 | ).result 77 | puts JSON.pretty_generate(tone) 78 | end 79 | -------------------------------------------------------------------------------- /examples/visual_recognition_v3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/visual_recognition_v3" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | test_url = "https://www.ibm.com/ibm/ginni/images/ginni_bio_780x981_v4_03162016.jpg" 19 | 20 | # If using IAM 21 | visual_recognition = IBMWatson::VisualRecognitionV3.new( 22 | version: "2018-03-19", 23 | authenticator: authenticator 24 | ) 25 | visual_recognition.service_url = "{service_url}" 26 | 27 | # cars = File.open(Dir.getwd + "/resources/cars.zip") 28 | # trucks = File.open(Dir.getwd + "/resources/trucks.zip") 29 | # puts JSON.pretty_generate(visual_recognition.create_classifier( 30 | # name: "Cars vs Trucks", 31 | # classname_positive_examples: cars, 32 | # negative_examples: trucks 33 | # ).result) 34 | 35 | File.open(Dir.getwd + "/resources/cars.zip") do |images_file| 36 | car_results = visual_recognition.classify( 37 | images_file: images_file, 38 | threshold: 0.1, 39 | classifier_ids: ["defaults"] 40 | ).result 41 | puts JSON.pretty_generate(car_results) 42 | end 43 | 44 | # puts JSON.pretty_generate(visual_recognition.get_classifier(classifier_id: "YOUR CLASSIFIER ID").result) 45 | 46 | # File.open(Dir.getwd + "/resources/car.jpg") do |image_file| 47 | # puts JSON.pretty_generate(visual_recognition.update_classifier( 48 | # classifier_id: "CarsvsTrucks_1479118188", 49 | # classname_positive_examples: image_file 50 | # ).result) 51 | # end 52 | 53 | url_result = visual_recognition.classify(url: test_url).result 54 | puts JSON.pretty_generate(url_result) 55 | 56 | # puts JSON.pretty_generate(visual_recognition.delete_classifier(classifier_id: "YOUR CLASSIFIER ID")) 57 | 58 | puts JSON.pretty_generate(visual_recognition.list_classifiers.result) 59 | -------------------------------------------------------------------------------- /examples/visual_recognition_v4.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "json" 4 | require "ibm_watson/authenticators" 5 | require "ibm_watson/visual_recognition_v4" 6 | 7 | # If using IAM 8 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 9 | apikey: "{iam_api_key}" 10 | ) 11 | 12 | # If you have username & password in your credentials use: 13 | # authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 14 | # username: "{username}", 15 | # password: "{password}" 16 | # ) 17 | 18 | # If using IAM 19 | visual_recognition = IBMWatson::VisualRecognitionV4.new( 20 | version: "2018-03-19", 21 | authenticator: authenticator 22 | ) 23 | visual_recognition.service_url = "{service_url}" 24 | 25 | ## Analyze multiple images 26 | image_file_1 = File.open(Dir.getwd + "/resources/dog.jpg") 27 | image_file_2 = File.open(Dir.getwd + "/resources/face.jpg") 28 | result = visual_recognition.analyze( 29 | images_file: [ 30 | { 31 | "data": image_file_1, 32 | "filename": "dog.jpg", 33 | "content_type": "image/jpeg" 34 | }, 35 | { 36 | "data": image_file_2, 37 | "filename": "face.jpg", 38 | "content_type": "image/jpeg" 39 | } 40 | ], 41 | collection_ids: @collection_id, 42 | features: "objects" 43 | ).result 44 | puts JSON.pretty_generate(result) 45 | 46 | ## Analyze images in zip file 47 | File.open(Dir.getwd + "/resources/cars.zip") do |image_file| 48 | car_results = visual_recognition.analyze( 49 | images_file: [ 50 | { 51 | "data": image_file, 52 | "filename": "dog.jpg", 53 | "content_type": "image/jpeg" 54 | } 55 | ], 56 | collection_ids: "{collection_id}", 57 | features: "objects" 58 | ).result 59 | puts JSON.pretty_generate(car_results) 60 | end 61 | 62 | ## Examples to create, list, get and delete Collections 63 | # puts JSON.pretty_generate(visual_recognition.create_collection.result) 64 | puts JSON.pretty_generate(visual_recognition.list_collections.result) 65 | puts JSON.pretty_generate(visual_recognition.get_collection(collection_id: "{collection_id}").result) 66 | puts JSON.pretty_generate(visual_recognition.delete_collection(collection_id: "{collection_id}")) 67 | -------------------------------------------------------------------------------- /ibm_watson.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path("lib", __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require "ibm_watson/version" 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = "ibm_watson" 9 | spec.version = IBMWatson::VERSION 10 | spec.authors = ["Max Nussbaum"] 11 | 12 | spec.summary = "Official client library to use the IBM Watson Services" 13 | spec.homepage = "https://www.github.com/watson-developer-cloud" 14 | spec.licenses = ["Apache-2.0"] 15 | spec.required_ruby_version = ">= 2.3" 16 | 17 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' 18 | # to allow pushing to a single host or delete this section to allow pushing to any host. 19 | if spec.respond_to?(:metadata) 20 | spec.metadata["allowed_push_host"] = "https://rubygems.org" 21 | spec.metadata["source_code_uri"] = "https://github.com/watson-developer-cloud/ruby-sdk" 22 | spec.metadata["documentation_uri"] = "https://cloud.ibm.com/developer/watson/documentation" 23 | else 24 | raise "RubyGems 2.0 or newer is required to protect against " \ 25 | "public gem pushes." 26 | end 27 | 28 | # Specify which files should be added to the gem when it is released. 29 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 30 | spec.files = Dir["rakefile", "{bin,lib,test}/**/*", "README*"] & `git ls-files -z`.split("\0") 31 | spec.bindir = "exe" 32 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 33 | spec.require_paths = ["lib"] 34 | 35 | spec.add_runtime_dependency "concurrent-ruby", "~> 1.0" 36 | spec.add_runtime_dependency "eventmachine", "~> 1.2" 37 | spec.add_runtime_dependency "faye-websocket", "~> 0.11" 38 | spec.add_runtime_dependency "http", "~> 4.4.0" 39 | spec.add_runtime_dependency "ibm_cloud_sdk_core", "~> 1.1.3" 40 | spec.add_runtime_dependency "jwt", "~> 2.2.1" 41 | 42 | spec.add_development_dependency "bundler", "~> 2.2" 43 | spec.add_development_dependency "codecov", "~> 0.1" 44 | spec.add_development_dependency "dotenv", "~> 2.4" 45 | spec.add_development_dependency "httplog", "~> 1.0" 46 | spec.add_development_dependency "minitest", "~> 5.11" 47 | spec.add_development_dependency "minitest-hooks", "~> 1.5" 48 | spec.add_development_dependency "minitest-reporters", "~> 1.3" 49 | spec.add_development_dependency "minitest-retry", "~> 0.1" 50 | spec.add_development_dependency "rake", "~> 13.0" 51 | spec.add_development_dependency "rubocop", "0.62" 52 | spec.add_development_dependency "simplecov", "~> 0.16" 53 | spec.add_development_dependency "webmock", "~> 3.4" 54 | end 55 | -------------------------------------------------------------------------------- /lib/ibm_watson.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("ibm_cloud_sdk_core") 4 | 5 | # Module for the Watson APIs 6 | module IBMWatson 7 | ApiException = IBMCloudSdkCore::ApiException 8 | DetailedResponse = IBMCloudSdkCore::DetailedResponse 9 | 10 | require_relative("./ibm_watson/assistant_v1.rb") 11 | require_relative("./ibm_watson/assistant_v2.rb") 12 | require_relative("./ibm_watson/text_to_speech_v1.rb") 13 | require_relative("./ibm_watson/discovery_v1.rb") 14 | require_relative("./ibm_watson/discovery_v2.rb") 15 | require_relative("./ibm_watson/natural_language_understanding_v1.rb") 16 | require_relative("./ibm_watson/speech_to_text_v1.rb") 17 | require_relative("./ibm_watson/language_translator_v3.rb") 18 | require_relative("./ibm_watson/websocket/recognize_callback.rb") 19 | require_relative("./ibm_watson/authenticators.rb") 20 | require_relative("./ibm_watson/common.rb") 21 | end 22 | -------------------------------------------------------------------------------- /lib/ibm_watson/authenticators.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("ibm_cloud_sdk_core") 4 | 5 | # Module for the Watson APIs 6 | module IBMWatson 7 | class Authenticators 8 | BasicAuthenticator = IBMCloudSdkCore::BasicAuthenticator 9 | BearerTokenAuthenticator = IBMCloudSdkCore::BearerTokenAuthenticator 10 | CloudPakForDataAuthenticator = IBMCloudSdkCore::CloudPakForDataAuthenticator 11 | ConfigBasedAuthenticatorFactory = IBMCloudSdkCore::ConfigBasedAuthenticatorFactory 12 | IamAuthenticator = IBMCloudSdkCore::IamAuthenticator 13 | NoAuthAuthenticator = IBMCloudSdkCore::NoAuthAuthenticator 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/ibm_watson/common.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "./version.rb" 4 | 5 | module IBMWatson 6 | # SDK Common class 7 | class Common 8 | def initialize(*); end 9 | 10 | def get_sdk_headers(service_name, service_version, operation_id) 11 | headers = {} 12 | user_agent_string = "watson-apis-ruby-sdk-" + IBMWatson::VERSION + " #{RbConfig::CONFIG["host"]}" 13 | user_agent_string += " #{RbConfig::CONFIG["RUBY_BASE_NAME"]}-#{RbConfig::CONFIG["RUBY_PROGRAM_VERSION"]}" 14 | 15 | headers["User-Agent"] = user_agent_string 16 | return headers if service_name.nil? || service_version.nil? || operation_id.nil? 17 | 18 | headers["X-IBMCloud-SDK-Analytics"] = "service_name=#{service_name};service_version=#{service_version};operation_id=#{operation_id}" 19 | headers 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/ibm_watson/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module IBMWatson 4 | VERSION = "2.1.3" 5 | end 6 | -------------------------------------------------------------------------------- /lib/ibm_watson/websocket/recognize_callback.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module IBMWatson 4 | # Abstract class for Recognize Callbacks 5 | class RecognizeCallback 6 | def initialize(*); end 7 | 8 | # Called when an interim result is received 9 | def on_transcription(transcript:); end 10 | 11 | # Called when a WebSocket connection is made 12 | def on_connected; end 13 | 14 | # Called when there is an error in the WebSocket connection 15 | def on_error(error:); end 16 | 17 | # Called when there is an inactivity timeout 18 | def on_inactivity_timeout(error:); end 19 | 20 | # Called when the service is listening for audio 21 | def on_listening; end 22 | 23 | # Called after the service returns the final result for the transcription 24 | def on_transcription_complete; end 25 | 26 | # Called when the service returns the final hypothesis 27 | def on_hypothesis(hypothesis:); end 28 | 29 | # Called when the service returns results. The data is returned unparsed 30 | def on_data(data:); end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/ibm_watson/websocket/speech_to_text_websocket_listener.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("eventmachine") 4 | require("faye/websocket") 5 | require("json") 6 | 7 | ONE_KB = 1024 8 | TIMEOUT_PREFIX = "No speech detected for" 9 | CLOSE_SIGNAL = 1000 10 | TEN_MILLISECONDS = 0.01 11 | 12 | # Class for interacting with the WebSocket API 13 | class WebSocketClient 14 | def initialize(audio: nil, chunk_data:, options:, recognize_callback:, service_url:, headers:, disable_ssl_verification: false) 15 | @audio = audio 16 | @options = options 17 | @callback = recognize_callback 18 | @bytes_sent = 0 19 | @headers = headers 20 | @is_listening = false 21 | @service_url = service_url 22 | @timer = nil 23 | @chunk_data = chunk_data 24 | @mic_running = false 25 | @data_size = audio.nil? ? 0 : @audio.size 26 | @queue = Queue.new 27 | @disable_ssl_verification = disable_ssl_verification 28 | end 29 | 30 | def start 31 | on_open = lambda do |event| 32 | on_connect(event) 33 | @client.send(build_start_message(options: @options)) 34 | @mic_running = true if @chunk_data 35 | send_audio(data: @audio) 36 | end 37 | 38 | on_message = lambda do |event| 39 | json_object = JSON.parse(event.data) 40 | if json_object.key?("error") 41 | error = json_object["error"] 42 | if error.start_with?(TIMEOUT_PREFIX) 43 | @callback.on_inactivity_timeout(error: error) 44 | else 45 | @callback.on_error(error: error) 46 | end 47 | elsif json_object.key?("state") 48 | if !@is_listening 49 | @is_listening = true 50 | else 51 | @client.send(build_close_message) 52 | @callback.on_transcription_complete 53 | @client.close(CLOSE_SIGNAL) 54 | end 55 | elsif json_object.key?("results") || json_object.key?("speaker_labels") 56 | hypothesis = "" 57 | unless json_object["results"].nil? && json_object["speaker_labels"].nil? 58 | hypothesis = json_object.dig("results", 0, "alternatives", 0, "transcript") 59 | b_final = json_object.dig("results", 0, "final") 60 | transcripts = extract_transcripts(alternatives: json_object.dig("results", 0, "alternatives")) 61 | 62 | @callback.on_hypothesis(hypothesis: hypothesis) if b_final 63 | 64 | @callback.on_transcription(transcript: transcripts) 65 | @callback.on_data(data: json_object) 66 | end 67 | end 68 | end 69 | 70 | on_close = lambda do |_event| 71 | @client = nil 72 | EM.stop_event_loop 73 | end 74 | 75 | on_error = lambda do |event| 76 | @callback.on_error(error: event) 77 | end 78 | 79 | EM&.reactor_thread&.join 80 | EM.run do 81 | if @disable_ssl_verification 82 | @service_url = @service_url.sub("wss:", "ws:") 83 | @client = Faye::WebSocket::Client.new(@service_url, nil, tls: { verify_peer: false, fail_if_no_peer_cert: false }, headers: @headers) 84 | else 85 | @client = Faye::WebSocket::Client.new(@service_url, nil, headers: @headers) 86 | end 87 | @client.onclose = on_close 88 | @client.onerror = on_error 89 | @client.onmessage = on_message 90 | @client.onopen = on_open 91 | @client.add_listener(Faye::WebSocket::API::Event.create("open")) 92 | @client.add_listener(Faye::WebSocket::API::Event.create("message")) 93 | @client.add_listener(Faye::WebSocket::API::Event.create("close")) 94 | @client.add_listener(Faye::WebSocket::API::Event.create("error")) 95 | end 96 | end 97 | 98 | def add_audio_chunk(chunk:) 99 | @data_size += chunk.size 100 | @queue << chunk 101 | end 102 | 103 | def stop_audio 104 | @mic_running = false 105 | end 106 | 107 | private 108 | 109 | def on_connect(_response) 110 | @callback.on_connected 111 | end 112 | 113 | def build_start_message(options:) 114 | options["action"] = "start" 115 | options.to_json 116 | end 117 | 118 | def build_close_message 119 | { "action" => "close" }.to_json 120 | end 121 | 122 | def send_audio(data:) 123 | if @chunk_data 124 | if @mic_running 125 | @queue.empty? ? send_chunk(chunk: nil, final: false) : send_chunk(chunk: @queue.pop(true), final: false) 126 | elsif @queue.length == 1 127 | send_chunk(chunk: @queue.pop(true), final: true) 128 | @queue.close 129 | @timer.cancel if @timer.respond_to?(:cancel) 130 | return 131 | else 132 | send_chunk(chunk: @queue.pop(true), final: false) unless @queue.empty? 133 | end 134 | else 135 | if @bytes_sent + ONE_KB >= @data_size 136 | send_chunk(chunk: data.read(ONE_KB), final: true) 137 | @timer.cancel if @timer.respond_to?(:cancel) 138 | return 139 | end 140 | send_chunk(chunk: data.read(ONE_KB), final: false) 141 | end 142 | @timer = EventMachine::Timer.new(TEN_MILLISECONDS) { send_audio(data: data) } 143 | end 144 | 145 | def extract_transcripts(alternatives:) 146 | transcripts = [] 147 | unless alternatives&.nil?.nil? 148 | alternatives.each do |alternative| 149 | transcript = {} 150 | transcript["confidence"] = alternative["confidence"] if alternative.key?("confidence") 151 | transcript["transcript"] = alternative["transcript"] 152 | transcripts << transcript 153 | end 154 | end 155 | transcripts 156 | end 157 | 158 | def send_chunk(chunk:, final: false) 159 | return if chunk.nil? 160 | 161 | @bytes_sent += chunk.size 162 | @client.send(chunk.bytes) 163 | @client.send({ "action" => "stop" }.to_json) if final 164 | @timer.cancel if @timer.respond_to?(:cancel) && final 165 | end 166 | end 167 | -------------------------------------------------------------------------------- /rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "dotenv/tasks" 4 | require "rake/testtask" 5 | require "rubocop/rake_task" 6 | 7 | task default: %w[def] 8 | 9 | RuboCop::RakeTask.new 10 | 11 | namespace :test do 12 | Rake::TestTask.new do |t| 13 | t.name = "unit" 14 | t.description = "Run unit tests" 15 | t.libs << "test" 16 | t.test_files = FileList["test/unit/*.rb"] 17 | t.verbose = true 18 | t.warning = true 19 | t.deps = [:rubocop] 20 | end 21 | 22 | Rake::TestTask.new do |t| 23 | t.name = "integration" 24 | t.description = "Run integration tests (put credentials in a .env file)" 25 | t.libs << "test" 26 | t.test_files = FileList["test/integration/*.rb"] 27 | t.verbose = true 28 | t.warning = true 29 | t.deps = %i[dotenv rubocop] 30 | end 31 | 32 | Rake::TestTask.new do |t| 33 | t.name = "appveyor_status" 34 | t.description = "Checks to ensure that AppVeyor tests pass before deploying from Travis" 35 | t.libs << "test" 36 | t.test_files = FileList["test/appveyor_status.rb"] 37 | t.verbose = false 38 | t.warning = false 39 | end 40 | end 41 | 42 | desc "Run unit & integration tests" 43 | task :test do 44 | Rake::Task["test:unit"].invoke 45 | Rake::Task["test:integration"].invoke 46 | end 47 | 48 | desc "Run tests and generate a code coverage report" 49 | task :coverage do 50 | ENV["COVERAGE"] = "true" if ENV["TRAVIS_RUBY_VERSION"] == "2.5.1" || ENV["CI"].nil? 51 | Rake::Task["test"].execute 52 | end 53 | 54 | task def: %i[coverage] do 55 | end 56 | -------------------------------------------------------------------------------- /resources/car.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watson-developer-cloud/ruby-sdk/c6dfaac119156fc7b5a01bf02cf7b06ceac82c81/resources/car.jpg -------------------------------------------------------------------------------- /resources/language_translator_model.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 |
6 | 7 | 8 | 9 | International Business Machines 10 | 11 | 12 | International Business Machines 13 | 14 | 15 | 16 | 17 | patent 18 | 19 | 20 | brevent 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /resources/nlu_categories_training.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "labels": [ 4 | "level1" 5 | ], 6 | "key_phrases": [ 7 | "key phrase", 8 | "key phrase 2" 9 | ] 10 | }, 11 | { 12 | "labels": [ 13 | "level1", 14 | "level2" 15 | ], 16 | "key_phrases": [ 17 | "key phrase 3", 18 | "key phrase 4" 19 | ] 20 | } 21 | ] 22 | 23 | -------------------------------------------------------------------------------- /resources/nlu_classifications_training.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "text": "Example 1", 4 | "labels": ["label1"] 5 | }, 6 | { 7 | "text": "Example 2", 8 | "labels": ["label1", "label2"] 9 | }, 10 | { 11 | "text": "Example 3", 12 | "labels": ["label1"] 13 | }, 14 | { 15 | "text": "Example 4", 16 | "labels": ["label1", "label2"] 17 | }, 18 | { 19 | "text": "Example 5", 20 | "labels": ["label1"] 21 | }, 22 | { 23 | "text": "Example 6", 24 | "labels": ["label1", "label2"] 25 | }, 26 | { 27 | "text": "Example 7", 28 | "labels": ["label1"] 29 | }, 30 | { 31 | "text": "Example 8", 32 | "labels": ["label1", "label2"] 33 | }, 34 | { 35 | "text": "Example 9", 36 | "labels": ["label1"] 37 | }, 38 | { 39 | "text": "Example 10", 40 | "labels": ["label1", "label2"] 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /resources/personality.txt: -------------------------------------------------------------------------------- 1 | Call me Ishmael. Some years ago-never mind how long precisely-having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off-then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me. 2 | There now is your insular city of the Manhattoes, belted round by wharves as Indian isles by coral reefs-commerce surrounds it with her surf. Right and left, the streets take you waterward. Its extreme downtown is the battery, where that noble mole is washed by waves, and cooled by breezes, which a few hours previous were out of sight of land. Look at the crowds of water-gazers there. 3 | Circumambulate the city of a dreamy Sabbath afternoon. Go from Corlears Hook to Coenties Slip, and from thence, by Whitehall, northward. What do you see?-Posted like silent sentinels all around the town, stand thousands upon thousands of mortal men fixed in ocean reveries. Some leaning against the spiles; some seated upon the pier-heads; some looking over the bulwarks of ships from China; some high aloft in the rigging, as if striving to get a still better seaward peep. But these are all landsmen; of week days pent up in lath and plaster-tied to counters, nailed to benches, clinched to desks. How then is this? Are the green fields gone? What do they here? 4 | But look! here come more crowds, pacing straight for the water, and seemingly bound for a dive. Strange! Nothing will content them but the extremest limit of the land; loitering under the shady lee of yonder warehouses will not suffice. No. They must get just as nigh the water as they possibly can without falling in. And there they stand-miles of them-leagues. Inlanders all, they come from lanes and alleys, streets and avenues-north, east, south, and west. Yet here they all unite. Tell me, does the magnetic virtue of the needles of the compasses of all those ships attract them thither? 5 | Once more. Say you are in the country; in some high land of lakes. Take almost any path you please, and ten to one it carries you down in a dale, and leaves you there by a pool in the stream. There is magic in it. Let the most absent-minded of men be plunged in his deepest reveries-stand that man on his legs, set his feet a-going, and he will infallibly lead you to water, if water there be in all that region. Should you ever be athirst in the great American desert, try this experiment, if your caravan happen to be supplied with a metaphysical professor. Yes, as every one knows, meditation and water are wedded for ever. 6 | But here is an artist. He desires to paint you the dreamiest, shadiest, quietest, most enchanting bit of romantic landscape in all the valley of the Saco. What is the chief element he employs? There stand his trees, each with a hollow trunk, as if a hermit and a crucifix were within; and here sleeps his meadow, and there sleep his cattle; and up from yonder cottage goes a sleepy smoke. Deep into distant woodlands winds a mazy way, reaching to overlapping spurs of mountains bathed in their hill-side blue. But though the picture lies thus tranced, and though this pine-tree shakes down its sighs like leaves upon this shepherd's head, yet all were vain, unless the shepherd's eye were fixed upon the magic stream before him. Go visit the Prairies in June, when for scores on scores of miles you wade knee-deep among Tiger-lilies-what is the one charm wanting?-Water-there is not a drop of water there! Were Niagara but a cataract of sand, would you travel your thousand miles to see it? Why did the poor poet of Tennessee, upon suddenly receiving two handfuls of silver, deliberate whether to buy him a coat, which he sadly needed, or invest his money in a pedestrian trip to Rockaway Beach? Why is almost every robust healthy boy with a robust healthy soul in him, at some time or other crazy to go to sea? Why upon your first voyage as a passenger, did you yourself feel such a mystical vibration, when first told that you and your ship were now out of sight of land? Why did the old Persians hold the sea holy? Why did the Greeks give it a separate deity, and own brother of Jove? Surely all this is not without meaning. And still deeper the meaning of that story of Narcissus, who because he could not grasp the tormenting, mild image he saw in the fountain, plunged into it and was drowned. But that same image, we ourselves see in all rivers and oceans. It is the image of the ungraspable phantom of life; and this is the key to it all. 7 | Now, when I say that I am in the habit of going to sea whenever I begin to grow hazy about the eyes, and begin to be over conscious of my lungs, I do not mean to have it inferred that I ever go to sea as a passenger. For to go as a passenger you must needs have a purse, and a purse is but a rag unless you have something in it. Besides, passengers get sea-sick-grow quarrelsome-don't sleep of nights-do not enjoy themselves much, as a general thing;-no, I never go as a passenger; nor, though I am something of a salt, do I ever go to sea as a Commodore, or a Captain, or a Cook. I abandon the glory and distinction of such offices to those who like them. For my part, I abominate all honourable respectable toils, trials, and tribulations of every kind whatsoever. It is quite as much as I can do to take care of myself, without taking care of ships, barques, brigs, schooners, and what not. And as for going as cook,-though I confess there is considerable glory in that, a cook being a sort of officer on ship-board-yet, somehow, I never fancied broiling fowls;-though once broiled, judiciously buttered, and judgmatically salted and peppered, there is no one who will speak more respectfully, not to say reverentially, of a broiled fowl than I will. It is out of the idolatrous dotings of the old Egyptians upon broiled ibis and roasted river horse, that you see the mummies of those creatures in their huge bake-houses the pyramids. 8 | No, when I go to sea, I go as a simple sailor, right before the mast, plumb down into the forecastle, aloft there to the royal mast-head. True, they rather order me about some, and make me jump from spar to spar, like a grasshopper in a May meadow. And at first, this sort of thing is unpleasant enough. It touches one's sense of honour, particularly if you come of an old established family in the land, the Van Rensselaers, or Randolphs, or Hardicanutes. And more than all, if just previous to putting your hand into the tar-pot, you have been lording it as a country schoolmaster, making the tallest boys stand in awe of you. The transition is a keen one, I assure you, from a schoolmaster to a sailor, and requires a strong decoction of Seneca and the Stoics to enable you to grin and bear it. But even this wears off in time. 9 | What of it, if some old hunks of a sea-captain orders me to get a broom and sweep down the decks? What does that indignity amount to, weighed, I mean, in the scales of the New Testament? Do you think the archangel Gabriel thinks anything the less of me, because I promptly and respectfully obey that old hunks in that particular instance? Who ain't a slave? Tell me that. Well, then, however the old sea-captains may order me about-however they may thump and punch me about, I have the satisfaction of knowing that it is all right; that everybody else is one way or other served in much the same way-either in a physical or metaphysical point of view, that is; and so the universal thump is passed round, and all hands should rub each other's shoulder-blades, and be content. 10 | Again, I always go to sea as a sailor, because they make a point of paying me for my trouble, whereas they never pay passengers a single penny that I ever heard of. On the contrary, passengers themselves must pay. And there is all the difference in the world between paying and being paid. The act of paying is perhaps the most uncomfortable infliction that the two orchard thieves entailed upon us. But BEING PAID,-what will compare with it? The urbane activity with which a man receives money is really marvellous, considering that we so earnestly believe money to be the root of all earthly ills, and that on no account can a monied man enter heaven. Ah! how cheerfully we consign ourselves to perdition! 11 | Finally, I always go to sea as a sailor, because of the wholesome exercise and pure air of the fore-castle deck. For as in this world, head winds are far more prevalent than winds from astern (that is, if you never violate the Pythagorean maxim), so for the most part the Commodore on the quarter-deck gets his atmosphere at second hand from the sailors on the forecastle. He thinks he breathes it first; but not so. In much the same way do the commonalty lead their leaders in many other things, at the same time that the leaders little suspect it. But wherefore it was that after having repeatedly smelt the sea as a merchant sailor, I should now take it into my head to go on a whaling voyage; this the invisible police officer of the Fates, who has the constant surveillance of me, and secretly dogs me, and influences me in some unaccountable way-he can better answer than any one else. And, doubtless, my going on this whaling voyage, formed part of the grand programme of Providence that was drawn up a long time ago. It came in as a sort of brief interlude and solo between more extensive performances. I take it that this part of the bill must have run something like this: 12 | "GRAND CONTESTED ELECTION FOR THE PRESIDENCY OF THE UNITED STATES. "WHALING VOYAGE BY ONE ISHMAEL. "BLOODY BATTLE IN AFFGHANISTAN." 13 | Though I cannot tell why it was exactly that those stage managers, the Fates, put me down for this shabby part of a whaling voyage, when others were set down for magnificent parts in high tragedies, and short and easy parts in genteel comedies, and jolly parts in farces-though I cannot tell why this was exactly; yet, now that I recall all the circumstances, I think I can see a little into the springs and motives which being cunningly presented to me under various disguises, induced me to set about performing the part I did, besides cajoling me into the delusion that it was a choice resulting from my own unbiased freewill and discriminating judgment. 14 | Chief among these motives was the overwhelming idea of the great whale himself. Such a portentous and mysterious monster roused all my curiosity. Then the wild and distant seas where he rolled his island bulk; the undeliverable, nameless perils of the whale; these, with all the attending marvels of a thousand Patagonian sights and sounds, helped to sway me to my wish. With other men, perhaps, such things would not have been inducements; but as for me, I am tormented with an everlasting itch for things remote. I love to sail forbidden seas, and land on barbarous coasts. Not ignoring what is good, I am quick to perceive a horror, and could still be social with it-would they let me-since it is but well to be on friendly terms with all the inmates of the place one lodges in. 15 | By reason of these things, then, the whaling voyage was welcome; the great flood-gates of the wonder-world swung open, and in the wild conceits that swayed me to my purpose, two and two there floated into my inmost soul, endless processions of the whale, and, mid most of them all, one grand hooded phantom, like a snow hill in the air. 16 | -------------------------------------------------------------------------------- /resources/problem.json: -------------------------------------------------------------------------------- 1 | { 2 | "subject": "phones", 3 | "columns": [ 4 | { 5 | "key": "price", 6 | "type": "numeric", 7 | "goal": "min", 8 | "is_objective": true, 9 | "full_name": "Price", 10 | "range": { 11 | "low": 0, 12 | "high": 400 13 | }, 14 | "format": "number:2" 15 | }, 16 | { 17 | "key": "weight", 18 | "type": "numeric", 19 | "goal": "min", 20 | "is_objective": true, 21 | "full_name": "Weight", 22 | "format": "number:0" 23 | }, 24 | { 25 | "key": "brand", 26 | "type": "categorical", 27 | "goal": "min", 28 | "is_objective": true, 29 | "full_name": "Brand", 30 | "range": [ 31 | "Apple", 32 | "HTC", 33 | "Samsung", 34 | "Sony" 35 | ], 36 | "preference": [ 37 | "Samsung", 38 | "Apple", 39 | "HTC" 40 | ] 41 | }, 42 | { 43 | "key": "rDate", 44 | "type": "datetime", 45 | "goal": "max", 46 | "full_name": "Release Date", 47 | "format": "date: 'MMM dd, yyyy'" 48 | } 49 | ], 50 | "options": [ 51 | { 52 | "key": "1", 53 | "name": "Samsung Galaxy S4", 54 | "values": { 55 | "price": 249, 56 | "weight": 130, 57 | "brand": "Samsung", 58 | "rDate": "2013-04-29T00:00:00Z" 59 | } 60 | }, 61 | { 62 | "key": "2", 63 | "name": "Apple iPhone 5", 64 | "values": { 65 | "price": 349, 66 | "weight": 112, 67 | "brand": "Apple", 68 | "rDate": "2012-09-21T00:00:00Z" 69 | } 70 | }, 71 | { 72 | "key": "3", 73 | "name": "HTC One", 74 | "values": { 75 | "price": 299, 76 | "weight": 112, 77 | "brand": "HTC", 78 | "rDate": "2013-03-01T00:00:00Z" 79 | } 80 | }, 81 | { 82 | "key": "4", 83 | "name": "Samsung Galaxy S5", 84 | "values": { 85 | "price": 349, 86 | "weight": 135, 87 | "brand": "Samsung", 88 | "rDate": "2014-04-29T00:00:00Z" 89 | } 90 | }, 91 | { 92 | "key": "5", 93 | "name": "Apple iPhone 6", 94 | "values": { 95 | "price": 399, 96 | "weight": 118, 97 | "brand": "Apple", 98 | "rDate": "2013-09-21T00:00:00Z" 99 | } 100 | }, 101 | { 102 | "key": "6", 103 | "name": "Apple iPhone 7", 104 | "values": { 105 | "price": 499, 106 | "weight": 118, 107 | "brand": "Apple", 108 | "rDate": "2014-09-21T00:00:00Z" 109 | } 110 | }, 111 | { 112 | "key": "7", 113 | "name": "Sony Xperia", 114 | "values": { 115 | "price": 199, 116 | "weight": 120, 117 | "brand": "Sony", 118 | "rDate": "2014-08-21T00:00:00Z" 119 | } 120 | } 121 | ] 122 | } 123 | -------------------------------------------------------------------------------- /resources/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Simple HTML Page 4 | 5 | 6 |

Chapter 1

7 |

The content of the first chapter.

8 | 9 | -------------------------------------------------------------------------------- /resources/sound-with-pause.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watson-developer-cloud/ruby-sdk/c6dfaac119156fc7b5a01bf02cf7b06ceac82c81/resources/sound-with-pause.wav -------------------------------------------------------------------------------- /resources/speech.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watson-developer-cloud/ruby-sdk/c6dfaac119156fc7b5a01bf02cf7b06ceac82c81/resources/speech.wav -------------------------------------------------------------------------------- /resources/speech_to_text/corpus-short-1.txt: -------------------------------------------------------------------------------- 1 | Am I at risk for health problems during travel 2 | Some people are more likely to have health problems when traveling outside the United States Visit your doctor before planning a trip to another country especially if you 3 | How Is Coronary Microvascular Disease Treated 4 | If youre diagnosed with coronary MVD and also have anemia you may benefit from treatment for that condition Anemia is thought to slow the growth of cells needed to repair damaged blood vessels 5 | What causes autoimmune hepatitis 6 | A combination of autoimmunity environmental triggers and a genetic predisposition can lead to autoimmune hepatitis 7 | What research is being done for Spinal Cord Injury 8 | The National Institute of Neurological Disorders and Stroke NINDS conducts spinal cord research in its laboratories at the National Institutes of Health NIH and also supports additional research through grants to major research institutions across the country Advances in research are giving doctors and patients hope that repairing injured spinal cords is a reachable goal Advances in basic research are also being matched by progress in clinical research especially in understanding the kinds of physical rehabilitation that work best to restore function Some of the more promising rehabilitation techniques are helping spinal cord injury patients become more mobile 9 | What is Osteogenesis imperfecta OI 10 | Osteogenesis imperfecta OI is a rare genetic disorder that like juvenile osteoporosis is characterized by bones that break easily often from little or no apparent cause 11 | -------------------------------------------------------------------------------- /resources/speech_to_text/corpus-short-2.txt: -------------------------------------------------------------------------------- 1 | Is there any treatment for Shaken Baby Syndrome 2 | Emergency treatment for a baby who has been shaken usually includes life-sustaining measures such as respiratory support and surgery to stop internal bleeding and bleeding in the brain Doctors may use brain scans such as MRI and CT to make a more definite diagnosis 3 | What is the prognosis for Wernicke-Korsakoff Syndrome 4 | Most symptoms can be reversed if detected and treated promptly However improvement in memory function is slow and usually incomplete Without treatment these disorders can be disabling and life-threatening 5 | Who gets diverticular disease 6 | Many people get diverticular disease Starting at age 40 the chance of getting it increases about every 10 years About half of people between the ages of 60 and 80 have diverticular disease Almost everyone over 80 has it 7 | What is a stoma 8 | During ostomy surgery of the bowel a surgeon creates a stoma by bringing the end of the intestine through an opening in the abdomen and attaching it to the skin to create an opening outside the body A stoma may be three-fourths of an inch to a little less than 2 inches wide The stoma is usually located in the lower part of the abdomen just below the beltline However sometimes the stoma is located in the upper abdomen The surgeon and a wound ostomy and continence WOC nurse or an enterostomal therapist will work together to select the best location for the stoma A removable external collection pouch called an ostomy pouch or ostomy appliance is attached to the stoma and worn outside the body to collect intestinal contents or stool Intestinal contents or stool passes through the stoma instead of passing through the anus The stoma has no muscle so it cannot control the flow of stool and the flow occurs whenever peristalsis occurs Ileostomy and colostomy are the two main types of ostomy surgery of the bowel during which a surgeon creates a stoma 9 | What is A chest x ray 10 | A chest x ray is a painless test that creates pictures of the structures in your chest such as your heart and lungs 11 | -------------------------------------------------------------------------------- /resources/test_enrichments.csv: -------------------------------------------------------------------------------- 1 | engine,gasket,piston,valves 2 | flag,green,yellow,red -------------------------------------------------------------------------------- /resources/tone-example-html.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "

Team, I know that times are tough!

Product sales have been disappointing for the past three quarters.

We have a competitive product, but we need to do a better job of selling it!

" 3 | } 4 | -------------------------------------------------------------------------------- /resources/tone-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Team, I know that times are tough! Product sales have been disappointing for the past three quarters. We have a competitive product, but we need to do a better job of selling it!" 3 | } 4 | -------------------------------------------------------------------------------- /resources/tone-v3-expect2.json: -------------------------------------------------------------------------------- 1 | { 2 | "utterances_tone": [ 3 | { 4 | "utterance_id": 0, 5 | "utterance_text": "I am very happy", 6 | "tones": [ 7 | { 8 | "score": 0.875529, 9 | "tone_id": "polite", 10 | "tone_name": "polite" 11 | }, 12 | { 13 | "score": 0.838693, 14 | "tone_id": "satisfied", 15 | "tone_name": "satisfied" 16 | }, 17 | { 18 | "score": 0.844135, 19 | "tone_id": "sympathetic", 20 | "tone_name": "sympathetic" 21 | }, 22 | { 23 | "score": 0.916255, 24 | "tone_id": "excited", 25 | "tone_name": "excited" 26 | } 27 | ] 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /resources/translation_doc.txt: -------------------------------------------------------------------------------- 1 | How are you? -------------------------------------------------------------------------------- /resources/weather_data_train.csv: -------------------------------------------------------------------------------- 1 | How hot is it today?,temperature 2 | Is it hot outside?,temperature 3 | Will it be uncomfortably hot?,temperature 4 | Will it be sweltering?,temperature 5 | How cold is it today?,temperature 6 | Is it cold outside?,temperature 7 | Will it be uncomfortably cold?,temperature 8 | Will it be frigid?,temperature 9 | What is the expected high for today?,temperature 10 | What is the expected temperature?,temperature 11 | Will high temperatures be dangerous?,temperature 12 | Is it dangerously cold?,temperature 13 | When will the heat subside?,temperature 14 | Is it hot?,temperature 15 | Is it cold?,temperature 16 | How cold is it now?,temperature 17 | Will we have a cold day today?,temperature 18 | When will the cold subside?,temperature 19 | What highs are we expecting?,temperature 20 | What lows are we expecting?,temperature 21 | Is it warm?,temperature 22 | Is it chilly?,temperature 23 | What's the current temp in Celsius?,temperature 24 | What is the temperature in Fahrenheit?,temperature 25 | Is it windy?,conditions 26 | Will it rain today?,conditions 27 | What are the chances for rain?,conditions 28 | Will we get snow?,conditions 29 | Are we expecting sunny conditions?,conditions 30 | Is it overcast?,conditions 31 | Will it be cloudy?,conditions 32 | How much rain will fall today?,conditions 33 | How much snow are we expecting?,conditions 34 | Is it windy outside?,conditions 35 | How much snow do we expect?,conditions 36 | Is the forecast calling for snow today?,conditions 37 | Will we see some sun?,conditions 38 | When will the rain subside?,conditions 39 | Is it cloudy?,conditions 40 | Is it sunny now?,conditions 41 | Will it rain?,conditions 42 | Will we have much snow?,conditions 43 | Are the winds dangerous?,conditions 44 | What is the expected snowfall today?,conditions 45 | Will it be dry?,conditions 46 | Will it be breezy?,conditions 47 | Will it be humid?,conditions 48 | What is today's expected humidity?,conditions 49 | Will the blizzard hit us?,conditions 50 | Is it drizzling?,conditions -------------------------------------------------------------------------------- /scripts/ruby-tasks/rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Dir.glob("./*.rake").each { |r| load r } 4 | 5 | task default: %w[patch] 6 | 7 | desc "Run post-generation patches" 8 | task :patch, [:path] do |_t, args| 9 | Rake::Task["speech_to_text"].invoke(args[:path]) 10 | end 11 | -------------------------------------------------------------------------------- /scripts/ruby-tasks/speech_to_text_v1.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | task default: %w[speech_to_text] 4 | 5 | desc "Run patches for speech to text" 6 | task :speech_to_text, [:path] do |_t, args| 7 | Rake::Task["speech_to_text:patch_recognize_using_websocket"].invoke(args[:path]) 8 | end 9 | 10 | namespace :speech_to_text do 11 | desc "Patch the recognize_using_websocket function" 12 | task :patch_recognize_using_websocket, [:path] do |_t, args| 13 | temp = File.read(args[:path] + "/speech_to_text_v1.rb") 14 | recognize_using_websocket = File.read(Dir.getwd + "/speech_to_text_v1/recognize_using_websocket.rb") 15 | temp = temp.sub(/(^\s*?##\n\s*?# @!method recognize\(.*?\n\s*?end\n($|\s*?#*?))/m) { |match| match + recognize_using_websocket } 16 | unless temp.nil? 17 | puts "Patch the speech to text - recognize_using_websocket function" 18 | File.open(args[:path] + "/speech_to_text_v1.rb", "w") do |file| 19 | file.write(temp) 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /scripts/ruby_tasks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # (C) Copyright IBM Corp. 2020. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 6 | # the License. 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 distributed under the License is distributed on 11 | # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | # specific language governing permissions and limitations under the License. 13 | # 14 | 15 | # Apply patches to the generated code from the Ruby SDK generator. 16 | # 17 | # Usage: 18 | # ruby-sdk/scripts/ruby_tasks.sh 19 | # 20 | # Example 21 | # bash ruby-sdk/scripts/ruby_tasks.sh "/Users/max/workspace/public/ruby-sdk/lib/ibm_watson" 22 | 23 | cd ./ruby-sdk/scripts/ruby-tasks 24 | rake patch[$1] 25 | cd ./../../.. 26 | -------------------------------------------------------------------------------- /test/appveyor_status.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("minitest/reporters") 4 | require("minitest/autorun") 5 | require("minitest/retry") 6 | require("http") 7 | require("json") 8 | 9 | Minitest::Retry.use! 10 | Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true), Minitest::Reporters::SpecReporter.new] 11 | 12 | # Test to run from Travis to ensure that AppVeyor tests pass before attempting to deploy to RubyGems 13 | class AppVeyorStatusTest < Minitest::Test 14 | def test_appveyor_status 15 | skip "Branch is NOT master and/or Ruby != 2.5.1, so AppVeyor check before deployment will not be run." if ENV["TRAVIS_BRANCH"] != "master" || ENV["TRAVIS_RUBY_VERSION"] != "2.5.1" 16 | client = HTTP::Client.new 17 | attempts = 0 18 | builds = JSON.parse(client.get("https://ci.appveyor.com/api/projects/maxnussbaum/ruby-sdk/history?recordsNumber=25&branch=master").body.to_s)["builds"] 19 | index = builds.index { |build| build["commitId"] == ENV["TRAVIS_COMMIT"] } 20 | flunk("An AppVeyor build for commit #{ENV["TRAVIS_COMMIT"]} could not be found") unless index.is_a?(Integer) 21 | current_build = builds[index] 22 | status = current_build["status"] 23 | puts("0 AppVeyor Status: #{status}") 24 | while status != "success" && status != "failed" && status != "cancelled" 25 | attempts += 1 26 | sleep(15) 27 | builds = JSON.parse(client.get("https://ci.appveyor.com/api/projects/maxnussbaum/ruby-sdk/history?recordsNumber=25&branch=master").body.to_s)["builds"] 28 | index = builds.index { |build| build["commitId"] == ENV["TRAVIS_COMMIT"] } 29 | current_build = builds[index] 30 | status = current_build["status"] 31 | puts("#{attempts} AppVeyor Status: #{status}") 32 | end 33 | if status == "success" 34 | assert(true) 35 | else 36 | flunk("AppVeyor tests have NOT passed! Please ensure that AppVeyor passes before deploying") 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /test/integration/test_assistant_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative("./../test_helper.rb") 4 | SimpleCov.command_name "test:integration" 5 | require("minitest/hooks/test") 6 | require("ibm_cloud_sdk_core") 7 | 8 | if !ENV["ASSISTANT_APIKEY"].nil? && !ENV["ASSISTANT_URL"].nil? 9 | # Integration tests for the Watson Assistant V1 Service 10 | class AssistantV1Test < Minitest::Test 11 | include Minitest::Hooks 12 | attr_accessor :service 13 | def before_all 14 | puts "before" 15 | authenticator = IBMWatson::Authenticators::ConfigBasedAuthenticatorFactory.new.get_authenticator(service_name: "assistant") 16 | @service = IBMWatson::AssistantV1.new( 17 | version: "2018-02-16", 18 | url: ENV["ASSISTANT_URL"], 19 | authenticator: authenticator 20 | ) 21 | @service.add_default_headers( 22 | headers: { 23 | "X-Watson-Learning-Opt-Out" => "1", 24 | "X-Watson-Test" => "1" 25 | } 26 | ) 27 | end 28 | 29 | def test_create_update_delete_workspace 30 | skip "Skip to allow for concurrent travis jobs" 31 | service_response = service.create_workspace( 32 | name: "Pizza app", 33 | description: "Pizza app", 34 | language: "en", 35 | metadata: {} 36 | ) 37 | workspace_id = service_response.result["workspace_id"] 38 | assert((200..299).cover?(service_response.status)) 39 | 40 | service_response = service.update_workspace( 41 | workspace_id: workspace_id, 42 | name: "Pizza app", 43 | description: "Pizza app", 44 | language: "en", 45 | metadata: {} 46 | ) 47 | assert((200..299).cover?(service_response.status)) 48 | 49 | service_response = service.delete_workspace( 50 | workspace_id: workspace_id 51 | ) 52 | assert(service_response.nil?) 53 | end 54 | 55 | def test_get_workspace 56 | service_response = service.get_workspace( 57 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"] 58 | ) 59 | assert((200..299).cover?(service_response.status)) 60 | end 61 | 62 | def test_list_workspaces 63 | service_response = service.list_workspaces 64 | assert((200..299).cover?(service_response.status)) 65 | end 66 | 67 | def test_create_update_delete_counterexample 68 | skip "Skip to allow for concurrent travis jobs" 69 | service_response = service.create_counterexample( 70 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 71 | text: "I want a large pizza please." 72 | ) 73 | assert((200..299).cover?(service_response.status)) 74 | 75 | service_response = service.update_counterexample( 76 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 77 | text: "I want a large pizza please.", 78 | new_text: "I want a large pizza please." 79 | ) 80 | assert((200..299).cover?(service_response.status)) 81 | 82 | service_response = service.get_counterexample( 83 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 84 | text: "I want a large pizza please." 85 | ) 86 | assert((200..299).cover?(service_response.status)) 87 | 88 | service_response = service.delete_counterexample( 89 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 90 | text: "I want a large pizza please." 91 | ) 92 | assert(service_response.nil?) 93 | end 94 | 95 | def test_list_counterexamples 96 | service_response = service.list_counterexamples( 97 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"] 98 | ) 99 | assert((200..299).cover?(service_response.status)) 100 | end 101 | 102 | def test_create_update_delete_entity 103 | skip "Skip to allow for concurrent travis jobs" 104 | service_response = service.create_entity( 105 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 106 | entity: "pizza_toppings", 107 | description: "Tasty pizza toppings", 108 | metadata: { "property" => "value" }, 109 | values: nil, 110 | fuzzy_match: nil 111 | ) 112 | assert((200..299).cover?(service_response.status)) 113 | 114 | service_response = service.update_entity( 115 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 116 | entity: "pizza_toppings", 117 | new_entity: "pizza_toppings" 118 | ) 119 | assert((200..299).cover?(service_response.status)) 120 | 121 | service_response = service.delete_entity( 122 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 123 | entity: "pizza_toppings" 124 | ) 125 | assert(service_response.nil?) 126 | end 127 | 128 | def test_get_entity 129 | service_response = service.get_entity( 130 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 131 | entity: "holiday", 132 | export: true 133 | ) 134 | assert((200..299).cover?(service_response.status)) 135 | end 136 | 137 | def test_list_entities 138 | service_response = service.list_entities( 139 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 140 | export: true 141 | ) 142 | assert((200..299).cover?(service_response.status)) 143 | end 144 | 145 | def test_create_update_delete_example 146 | skip "Skip to allow for concurrent travis jobs" 147 | service_response = service.create_example( 148 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 149 | intent: "Cancel", 150 | text: "Gimme a pizza with pepperoni" 151 | ) 152 | assert((200..299).cover?(service_response.status)) 153 | 154 | service_response = service.update_example( 155 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 156 | intent: "Cancel", 157 | text: "Gimme a pizza with pepperoni", 158 | new_text: "Gimme a pizza with pepperoni" 159 | ) 160 | assert((200..299).cover?(service_response.status)) 161 | 162 | service_response = service.delete_example( 163 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 164 | intent: "Cancel", 165 | text: "Gimme a pizza with pepperoni" 166 | ) 167 | assert(service_response.nil?) 168 | end 169 | 170 | def test_get_example 171 | service_response = service.get_example( 172 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 173 | intent: "Cancel", 174 | text: "forget it" 175 | ) 176 | assert((200..299).cover?(service_response.status)) 177 | end 178 | 179 | def test_list_examples 180 | service_response = service.list_examples( 181 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 182 | intent: "Cancel" 183 | ) 184 | assert((200..299).cover?(service_response.status)) 185 | end 186 | 187 | def test_create_update_delete_intent 188 | skip "Skip to allow for concurrent travis jobs" 189 | service_response = service.create_intent( 190 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 191 | intent: "pizza_order", 192 | description: "User wants to start a new pizza order" 193 | ) 194 | assert((200..299).cover?(service_response.status)) 195 | 196 | service_response = service.update_intent( 197 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 198 | intent: "pizza_order", 199 | new_intent: "pizza_order", 200 | new_description: "User wants to start a new pizza order" 201 | ) 202 | assert((200..299).cover?(service_response.status)) 203 | 204 | service_response = service.delete_intent( 205 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 206 | intent: "pizza_order" 207 | ) 208 | assert(service_response.nil?) 209 | end 210 | 211 | def test_get_intent 212 | service_response = service.get_intent( 213 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 214 | intent: "Cancel", 215 | export: false 216 | ) 217 | assert((200..299).cover?(service_response.status)) 218 | end 219 | 220 | def test_list_intents 221 | service_response = service.list_intents( 222 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 223 | export: false 224 | ) 225 | assert((200..299).cover?(service_response.status)) 226 | end 227 | 228 | def test_list_logs 229 | service_response = service.list_logs( 230 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"] 231 | ) 232 | assert((200..299).cover?(service_response.status)) 233 | end 234 | 235 | def test_list_all_logs 236 | service_response = service.list_all_logs( 237 | filter: "language::en,request.context.metadata.deployment::deployment_1" 238 | ) 239 | assert((200..299).cover?(service_response.status)) 240 | end 241 | 242 | def test_message 243 | service_response = service.message( 244 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 245 | input: { "text" => "Turn on the lights" }, 246 | context: nil 247 | ) 248 | assert((200..299).cover?(service_response.status)) 249 | 250 | context = service_response.result["context"] 251 | service_response = service.message( 252 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 253 | input: { "text" => "Turn on the lights" }, 254 | context: context 255 | ) 256 | assert((200..299).cover?(service_response.status)) 257 | end 258 | 259 | def test_create_update_delete_synonym 260 | skip "Skip to allow for concurrent travis jobs" 261 | service_response = service.create_synonym( 262 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 263 | entity: "holiday", 264 | value: "labor day", 265 | synonym: "a" 266 | ) 267 | assert((200..299).cover?(service_response.status)) 268 | 269 | service_response = service.update_synonym( 270 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 271 | entity: "holiday", 272 | value: "labor day", 273 | synonym: "a", 274 | new_synonym: "a" 275 | ) 276 | assert((200..299).cover?(service_response.status)) 277 | 278 | service_response = service.delete_synonym( 279 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 280 | entity: "holiday", 281 | value: "labor day", 282 | synonym: "a" 283 | ) 284 | assert(service_response.nil?) 285 | end 286 | 287 | def test_get_synonym 288 | service_response = service.get_synonym( 289 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 290 | entity: "holiday", 291 | value: "thanksgiving", 292 | synonym: "turkey day" 293 | ) 294 | assert((200..299).cover?(service_response.status)) 295 | end 296 | 297 | def test_list_synonyms 298 | service_response = service.list_synonyms( 299 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 300 | entity: "holiday", 301 | value: "new years eve" 302 | ) 303 | assert((200..299).cover?(service_response.status)) 304 | end 305 | 306 | def test_create_update_delete_value 307 | skip "Skip to allow for concurrent travis jobs" 308 | service_response = service.create_value( 309 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 310 | entity: "holiday", 311 | value: "aeiou" 312 | ) 313 | assert((200..299).cover?(service_response.status)) 314 | 315 | service_response = service.update_value( 316 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 317 | entity: "holiday", 318 | value: "aeiou", 319 | new_value: "BBQ sauce", 320 | new_metadata: { "code" => 1422 }, 321 | new_synonyms: nil 322 | ) 323 | assert((200..299).cover?(service_response.status)) 324 | 325 | service_response = service.delete_value( 326 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 327 | entity: "holiday", 328 | value: "BBQ sauce" 329 | ) 330 | assert(service_response.nil?) 331 | end 332 | 333 | def test_get_value 334 | service_response = service.get_value( 335 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 336 | entity: "holiday", 337 | value: "christmas", 338 | export: true 339 | ) 340 | assert((200..299).cover?(service_response.status)) 341 | end 342 | 343 | def test_list_values 344 | service_response = service.list_values( 345 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 346 | entity: "holiday", 347 | export: true 348 | ) 349 | assert((200..299).cover?(service_response.status)) 350 | end 351 | 352 | def test_dialog_nodes 353 | skip "Skip to allow for concurrent travis jobs" 354 | 355 | service_response = service.create_dialog_node( 356 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 357 | dialog_node: "location-done" 358 | ) 359 | assert((200..299).cover?(service_response.status)) 360 | 361 | service_response = service.delete_dialog_node( 362 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 363 | dialog_node: "location-done" 364 | ) 365 | assert(service_response.nil?) 366 | 367 | service_response = service.get_dialog_node( 368 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"], 369 | dialog_node: "Hours of Operation" 370 | ) 371 | assert((200..299).cover?(service_response.status)) 372 | 373 | service_response = service.list_dialog_nodes( 374 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"] 375 | ) 376 | assert((200..299).cover?(service_response.status)) 377 | end 378 | 379 | def test_delete_user_data 380 | service_response = service.delete_user_data( 381 | customer_id: "id" 382 | ) 383 | assert(service_response.nil?) 384 | end 385 | 386 | def test_bulk_classify 387 | skip "Covered with the unit test. No need to run it here" 388 | 389 | service_response = service.bulk_classify( 390 | workspace_id: ENV["ASSISTANT_WORKSPACE_ID"] 391 | ) 392 | assert(service_response.nil?) 393 | end 394 | end 395 | else 396 | class AssistantV1Test < Minitest::Test 397 | def test_missing_credentials_skip_integration 398 | skip "Skip assistant integration tests because credentials have not been provided" 399 | end 400 | end 401 | end 402 | -------------------------------------------------------------------------------- /test/integration/test_assistant_v2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative("./../test_helper.rb") 4 | SimpleCov.command_name "test:integration" 5 | require("minitest/hooks/test") 6 | require("ibm_cloud_sdk_core") 7 | 8 | if !ENV["ASSISTANT_APIKEY"].nil? && !ENV["ASSISTANT_URL"].nil? 9 | # Integration tests for the Watson Assistant V2 Service 10 | class AssistantV2Test < Minitest::Test 11 | include Minitest::Hooks 12 | attr_accessor :service 13 | def before_all 14 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 15 | apikey: ENV["ASSISTANT_APIKEY"] 16 | ) 17 | @service = IBMWatson::AssistantV2.new( 18 | version: "2018-12-31", 19 | authenticator: authenticator, 20 | url: ENV["ASSISTANT_URL"], 21 | assistant_id: ENV["ASSISTANT_ASSISTANT_ID"] 22 | ) 23 | service.add_default_headers( 24 | headers: { 25 | "X-Watson-Learning-Opt-Out" => "1", 26 | "X-Watson-Test" => "1" 27 | } 28 | ) 29 | end 30 | 31 | def test_create_delete_session_and_message 32 | service_response = service.create_session( 33 | assistant_id: ENV["ASSISTANT_ASSISTANT_ID"] 34 | ) 35 | session_id = service_response.result["session_id"] 36 | assert((200..299).cover?(service_response.status)) 37 | 38 | service_response = service.message( 39 | assistant_id: ENV["ASSISTANT_ASSISTANT_ID"], 40 | session_id: session_id, 41 | input: { "text" => "Turn on the lights" }, 42 | context: nil 43 | ) 44 | assert((200..299).cover?(service_response.status)) 45 | 46 | context = service_response.result["context"] 47 | service_response = service.message( 48 | assistant_id: ENV["ASSISTANT_ASSISTANT_ID"], 49 | session_id: session_id, 50 | input: { "text" => "Turn on the lights" }, 51 | context: context 52 | ) 53 | assert((200..299).cover?(service_response.status)) 54 | 55 | service_response = service.message_stateless( 56 | assistant_id: ENV["ASSISTANT_ASSISTANT_ID"], 57 | input: { "text" => "Turn on the lights" }, 58 | context: nil 59 | ) 60 | assert((200..299).cover?(service_response.status)) 61 | 62 | service.delete_session( 63 | assistant_id: ENV["ASSISTANT_ASSISTANT_ID"], 64 | session_id: session_id 65 | ) 66 | end 67 | 68 | def test_list_logs 69 | skip "Premium plan only. Need Premium credentials" 70 | 71 | service_response = service.list_logs( 72 | assistant_id: ENV["ASSISTANT_ASSISTANT_ID"] 73 | ) 74 | assert((200..299).cover?(service_response.status)) 75 | end 76 | 77 | def test_delete_user_data 78 | skip "Covered with the unit test. No need to run it here" 79 | 80 | service_response = service.delete_user_data( 81 | customer_id: ENV["ASSISTANT_ASSISTANT_ID"] 82 | ) 83 | assert(service_response.nil?) 84 | end 85 | 86 | def test_bulk_classify 87 | skip "Covered with the unit test. No need to run it here" 88 | 89 | service_response = service.bulk_classify( 90 | skill_id: ENV["ASSISTANT_WORKSPACE_ID"] 91 | ) 92 | assert(service_response.nil?) 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /test/integration/test_discovery_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative("./../test_helper.rb") 4 | require("minitest/hooks/test") 5 | 6 | if !ENV["DISCOVERY_APIKEY"].nil? && !ENV["DISCOVERY_URL"].nil? 7 | # Integration tests for the Discovery V1 Service 8 | class DiscoveryV1Test < Minitest::Test 9 | include Minitest::Hooks 10 | attr_accessor :service, :environment_id, :collection_id 11 | 12 | def before_all 13 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 14 | apikey: ENV["DISCOVERY_APIKEY"] 15 | ) 16 | @service = IBMWatson::DiscoveryV1.new( 17 | authenticator: authenticator, 18 | url: ENV["DISCOVERY_URL"], 19 | version: "2018-03-05" 20 | ) 21 | @environment_id = ENV["DISCOVERY_ENVIRONMENT_ID"] 22 | @collection_id = ENV["DISCOVERY_COLLECTION_ID"] 23 | @service.add_default_headers( 24 | headers: { 25 | "X-Watson-Learning-Opt-Out" => "1", 26 | "X-Watson-Test" => "1" 27 | } 28 | ) 29 | end 30 | 31 | def test_environments 32 | envs = @service.list_environments.result 33 | refute(envs.nil?) 34 | env = @service.get_environment( 35 | environment_id: envs["environments"][0]["environment_id"] 36 | ) 37 | refute(env.nil?) 38 | end 39 | 40 | def test_configurations 41 | configs = @service.list_configurations( 42 | environment_id: @environment_id 43 | ).result 44 | refute(configs.nil?) 45 | 46 | skip "Skip to allow for concurrent travis jobs" 47 | name = "test" + ("A".."Z").to_a.sample 48 | new_configuration_id = @service.create_configuration( 49 | environment_id: @environment_id, 50 | name: name, 51 | description: "creating new config for ruby sdk" 52 | ).result 53 | new_configuration_id = new_configuration_id["configuration_id"] 54 | refute(new_configuration_id.nil?) 55 | @service.get_configuration( 56 | environment_id: @environment_id, 57 | configuration_id: new_configuration_id 58 | ) 59 | 60 | updated_config = @service.update_configuration( 61 | environment_id: @environment_id, 62 | configuration_id: new_configuration_id, 63 | name: "lala" 64 | ).result 65 | updated_config = updated_config 66 | assert_equal("lala", updated_config["name"]) 67 | 68 | deleted_config = @service.delete_configuration( 69 | environment_id: @environment_id, 70 | configuration_id: new_configuration_id 71 | ).result 72 | deleted_config = deleted_config 73 | assert_equal("deleted", deleted_config["status"]) 74 | end 75 | 76 | def test_collections_fields_query_and_expansions 77 | skip "Time consuming" 78 | name = "Example collection for ruby" + ("A".."Z").to_a.sample 79 | new_collection_id = @service.create_collection( 80 | environment_id: @environment_id, 81 | name: name, 82 | description: "Integration test for ruby sdk" 83 | ).result 84 | new_collection_id = new_collection_id["collection_id"] 85 | refute(new_collection_id.nil?) 86 | 87 | collection_status = { "status" => "pending" } 88 | while collection_status["status"] == "pending" 89 | sleep(1) 90 | collection_status = @service.get_collection( 91 | environment_id: @environment_id, 92 | collection_id: new_collection_id 93 | ).result 94 | collection_status = collection_status 95 | end 96 | updated_collection = @service.update_collection( 97 | environment_id: @environment_id, 98 | collection_id: new_collection_id, 99 | name: name, 100 | description: "Updating description" 101 | ).result 102 | updated_collection = updated_collection 103 | assert_equal("Updating description", updated_collection["description"]) 104 | 105 | fields = @service.list_fields( 106 | environment_id: @environment_id, 107 | collection_ids: [new_collection_id, @collection_id] 108 | ) 109 | refute(fields.nil?) 110 | 111 | query_results = @service.query( 112 | environment_id: @environment_id, 113 | collection_id: new_collection_id, 114 | filter: "extracted_metadata.sha1::9181d244*", 115 | return_fields: "extracted_metadata.sha1" 116 | ).result 117 | refute(query_results.nil?) 118 | 119 | @service.create_expansions( 120 | environment_id: @environment_id, 121 | collection_id: new_collection_id, 122 | expansions: [ 123 | { 124 | "input_terms" => ["a"], 125 | "expanded_terms" => ["aa"] 126 | } 127 | ] 128 | ) 129 | expansions = @service.list_expansions( 130 | environment_id: @environment_id, 131 | collection_id: new_collection_id 132 | ).result 133 | expansions = expansions 134 | refute(expansions["expansions"].nil?) 135 | 136 | @service.delete_expansions( 137 | environment_id: @environment_id, 138 | collection_id: new_collection_id 139 | ) 140 | deleted_collection = @service.delete_collection( 141 | environment_id: @environment_id, 142 | collection_id: new_collection_id 143 | ).result 144 | deleted_collection = deleted_collection 145 | assert_equal("deleted", deleted_collection["status"]) 146 | end 147 | 148 | def test_documents 149 | skip "Time consuming" 150 | add_doc = nil 151 | File.open(Dir.getwd + "/resources/simple.html") do |file_info| 152 | add_doc = @service.add_document( 153 | environment_id: @environment_id, 154 | collection_id: @collection_id, 155 | file: file_info 156 | ).result 157 | end 158 | add_doc = add_doc 159 | refute(add_doc["document_id"].nil?) 160 | 161 | doc_status = { "status" => "processing" } 162 | while doc_status["status"] == "processing" 163 | sleep(1) 164 | doc_status = @service.get_document_status( 165 | environment_id: @environment_id, 166 | collection_id: @collection_id, 167 | document_id: add_doc["document_id"] 168 | ).result 169 | doc_status = doc_status 170 | end 171 | assert_equal("available", doc_status["status"]) 172 | 173 | update_doc = nil 174 | File.open(Dir.getwd + "/resources/simple.html") do |file_info| 175 | update_doc = @service.update_document( 176 | environment_id: @environment_id, 177 | collection_id: @collection_id, 178 | document_id: add_doc["document_id"], 179 | file: file_info, 180 | filename: "newname.html" 181 | ).result 182 | end 183 | refute(update_doc.nil?) 184 | 185 | doc_status = { "status" => "processing" } 186 | while doc_status["status"] == "processing" 187 | sleep(1) 188 | doc_status = @service.get_document_status( 189 | environment_id: @environment_id, 190 | collection_id: @collection_id, 191 | document_id: add_doc["document_id"] 192 | ).result 193 | doc_status = doc_status 194 | end 195 | assert_equal("available", doc_status["status"]) 196 | 197 | delete_doc = @service.delete_document( 198 | environment_id: @environment_id, 199 | collection_id: @collection_id, 200 | document_id: add_doc["document_id"] 201 | ).result 202 | delete_doc = delete_doc 203 | assert_equal("deleted", delete_doc["status"]) 204 | end 205 | 206 | def test_list_credentials 207 | credentials = @service.list_credentials( 208 | environment_id: @environment_id 209 | ).result 210 | refute(credentials.nil?) 211 | end 212 | 213 | def test_list_gateways 214 | response = @service.list_gateways( 215 | environment_id: @environment_id 216 | ).result 217 | refute(response.nil?) 218 | end 219 | 220 | def test_create_get_delete_gateways 221 | skip 222 | gateway = @service.create_gateway( 223 | environment_id: @environment_id, 224 | name: "test" 225 | ).result 226 | refute(gateway.nil?) 227 | 228 | response = @service.get_gateway( 229 | environment_id: @environment_id, 230 | gateway_id: gateway["gateway_id"] 231 | ).result 232 | refute(response.nil?) 233 | 234 | response = @service.delete_gateway( 235 | environment_id: @environment_id, 236 | gateway_id: gateway["gateway_id"] 237 | ).result 238 | refute(response.nil?) 239 | end 240 | end 241 | else 242 | class DiscoveryV1Test < Minitest::Test 243 | def test_missing_credentials_skip_integration 244 | skip "Skip discovery integration tests because credentials have not been provided" 245 | end 246 | end 247 | end 248 | -------------------------------------------------------------------------------- /test/integration/test_discovery_v2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative("./../test_helper.rb") 4 | require("minitest/hooks/test") 5 | 6 | if !ENV["DISCOVERY_V2_APIKEY"].nil? 7 | # Integration tests for the Discovery V2 Service 8 | class DiscoveryV2Test < Minitest::Test 9 | include Minitest::Hooks 10 | attr_accessor :service, :environment_id, :collection_id 11 | 12 | def before_all 13 | # authenticator = IBMWatson::Authenticators::BearerTokenAuthenticator.new( 14 | # bearer_token: ENV["DISCOVERY_V2_TOKEN"] 15 | # ) 16 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 17 | apikey: ENV["DISCOVERY_V2_APIKEY"] 18 | ) 19 | @service = IBMWatson::DiscoveryV2.new( 20 | authenticator: authenticator, 21 | version: "2019-11-21" 22 | ) 23 | @service.service_url = ENV["DISCOVERY_V2_URL"] 24 | @service.configure_http_client(disable_ssl_verification: true) 25 | @project_id = ENV["DISCOVERY_V2_PROJECT_ID"] 26 | @collection_id = ENV["DISCOVERY_V2_COLLECTION_ID"] 27 | @document_id = nil 28 | @service.add_default_headers( 29 | headers: { 30 | "X-Watson-Learning-Opt-Out" => "1", 31 | "X-Watson-Test" => "1" 32 | } 33 | ) 34 | end 35 | 36 | def test_list_collections 37 | service_response = service.list_collections( 38 | project_id: @project_id 39 | ) 40 | refute(service_response.result["collections"].nil?) 41 | end 42 | 43 | def test_query 44 | service_response = service.query( 45 | project_id: @project_id, 46 | count: 10 47 | ) 48 | refute(service_response.result["results"].nil?) 49 | end 50 | 51 | def test_get_autocompletion 52 | service_response = service.get_autocompletion( 53 | project_id: @project_id, 54 | prefix: "hi how are " 55 | ) 56 | refute(service_response.result["completions"].nil?) 57 | end 58 | 59 | def test_query_notices 60 | service_response = service.query_notices( 61 | project_id: @project_id 62 | ) 63 | refute(service_response.result.nil?) 64 | end 65 | 66 | def test_list_fields 67 | service_response = service.list_fields( 68 | project_id: @project_id, 69 | collection_ids: [@collection_id] 70 | ) 71 | refute(service_response.result.nil?) 72 | end 73 | 74 | def test_get_component_settings 75 | service_response = service.get_component_settings( 76 | project_id: @project_id 77 | ) 78 | refute(service_response.result.nil?) 79 | end 80 | 81 | def test_add_update_delete_document 82 | File.open(Dir.getwd + "/resources/simple.html") do |file_info| 83 | service_response = service.add_document( 84 | project_id: @project_id, 85 | collection_id: @collection_id, 86 | file: file_info 87 | ) 88 | refute(service_response.nil?) 89 | @document_id = service_response.result["document_id"] 90 | end 91 | return if @document_id.nil? 92 | 93 | service_response = service.update_document( 94 | project_id: @project_id, 95 | collection_id: @collection_id, 96 | document_id: @document_id, 97 | file: "file", 98 | filename: "file.name" 99 | ) 100 | refute(service_response.result.nil?) 101 | service.delete_document( 102 | project_id: @project_id, 103 | collection_id: @collection_id, 104 | document_id: @document_id 105 | ) 106 | end 107 | 108 | def test_list_training_queries 109 | service_response = service.list_training_queries( 110 | project_id: @project_id 111 | ) 112 | refute(service_response.nil?) 113 | end 114 | 115 | def test_create_get_update_training_query 116 | service_response = service.create_training_query( 117 | project_id: @project_id, 118 | natural_language_query: "How is the weather today?", 119 | examples: [] 120 | ) 121 | query_id = service_response.result["query_id"] 122 | refute(service_response.nil?) 123 | # puts JSON.pretty_generate(service_response.result) 124 | 125 | service_response = service.get_training_query( 126 | project_id: @project_id, 127 | query_id: query_id 128 | ) 129 | refute(service_response.nil?) 130 | 131 | service_response = service.update_training_query( 132 | project_id: @project_id, 133 | query_id: query_id, 134 | natural_language_query: "How is the weather tomorrow?", 135 | examples: [] 136 | ) 137 | refute(service_response.nil?) 138 | 139 | service_response = service.delete_training_query( 140 | project_id: @project_id, 141 | query_id: query_id 142 | ) 143 | assert(service_response.nil?) 144 | end 145 | 146 | def test_create_get_update_delete_collection 147 | service_response = service.create_collection( 148 | project_id: @project_id, 149 | name: "ruby_collection" 150 | ) 151 | create_collection_id = service_response.result["collection_id"] 152 | assert((200..299).cover?(service_response.status)) 153 | 154 | service_response = service.get_collection( 155 | project_id: @project_id, 156 | collection_id: create_collection_id 157 | ) 158 | assert((200..299).cover?(service_response.status)) 159 | 160 | service_response = service.update_collection( 161 | project_id: @project_id, 162 | collection_id: create_collection_id 163 | ) 164 | assert((200..299).cover?(service_response.status)) 165 | 166 | service_response = service.delete_collection( 167 | project_id: @project_id, 168 | collection_id: create_collection_id 169 | ) 170 | assert(service_response.nil?) 171 | end 172 | 173 | def test_create_list_get_update_delete_project 174 | service_response = service.create_project( 175 | name: "ruby_project", 176 | type: "document_retrieval" 177 | ) 178 | create_project_id = service_response.result["project_id"] 179 | assert((200..299).cover?(service_response.status)) 180 | 181 | service_response = service.list_projects 182 | assert((200..299).cover?(service_response.status)) 183 | 184 | service_response = service.get_project( 185 | project_id: create_project_id 186 | ) 187 | assert((200..299).cover?(service_response.status)) 188 | 189 | service_response = service.update_project( 190 | project_id: create_project_id 191 | ) 192 | assert((200..299).cover?(service_response.status)) 193 | 194 | service_response = service.delete_project( 195 | project_id: create_project_id 196 | ) 197 | assert(service_response.nil?) 198 | end 199 | 200 | def test_create_list_get_update_delete_enrichment 201 | enrichment_metadata = { 202 | name: "RUBY enrichment", 203 | description: "test dictionary", 204 | type: "dictionary", 205 | options: { 206 | languages: ["en"], 207 | entity_type: "keyword" 208 | } 209 | } 210 | 211 | em_json = JSON[enrichment_metadata] 212 | # {"name":"Dictionary","description":"test dictionary","type":"dictionary","options":{"languages":["en"],"entity_type":"keyword"}} 213 | enrichment_data = File.open(Dir.getwd + "/resources/test_enrichments.csv") 214 | 215 | service_response = service.create_enrichment( 216 | project_id: @project_id, 217 | file: enrichment_data, 218 | enrichment: em_json 219 | ) 220 | assert((200..299).cover?(service_response.status)) 221 | create_enrichment_id = service_response.result["enrichment_id"] 222 | 223 | service_response = service.list_enrichments( 224 | project_id: @project_id 225 | ) 226 | assert((200..299).cover?(service_response.status)) 227 | 228 | service_response = service.get_enrichment( 229 | project_id: @project_id, 230 | enrichment_id: create_enrichment_id 231 | ) 232 | assert((200..299).cover?(service_response.status)) 233 | 234 | service_response = service.update_enrichment( 235 | project_id: @project_id, 236 | enrichment_id: create_enrichment_id, 237 | name: "New RUBY Name" 238 | ) 239 | assert((200..299).cover?(service_response.status)) 240 | 241 | service_response = service.delete_enrichment( 242 | project_id: @project_id, 243 | enrichment_id: create_enrichment_id 244 | ) 245 | assert(service_response.nil?) 246 | end 247 | 248 | def test_query_collection_notices 249 | service_response = service.query_collection_notices( 250 | project_id: @project_id, 251 | collection_id: @collection_id 252 | ) 253 | refute(service_response.result.nil?) 254 | end 255 | 256 | def test_delete_user_data 257 | skip "Covered with the unit test. No need to run it here" 258 | 259 | service_response = service.delete_user_data( 260 | customer_id: "000010000" 261 | ) 262 | assert(service_response.nil?) 263 | end 264 | 265 | def test_analyze_document 266 | skip "CPD only. Do not run on premium" 267 | analyze_data = File.open(Dir.getwd + "/resources/problem.json") 268 | 269 | service_response = service.analyze_document( 270 | project_id: @project_id, 271 | collection_id: @collection_id, 272 | file: analyze_data, 273 | file_content_type: "application/json" 274 | ) 275 | assert((200..299).cover?(service_response.status)) 276 | refute(service_response.nil?) 277 | end 278 | end 279 | else 280 | class DiscoveryV2Test < Minitest::Test 281 | def test_missing_credentials_skip_integration 282 | skip "Skip discovery integration tests because credentials have not been provided" 283 | end 284 | end 285 | end 286 | -------------------------------------------------------------------------------- /test/integration/test_language_translator_v3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("json") 4 | require_relative("./../test_helper.rb") 5 | require("minitest/hooks/test") 6 | 7 | if !ENV["LANGUAGE_TRANSLATOR_APIKEY"].nil? && !ENV["LANGUAGE_TRANSLATOR_URL"].nil? 8 | # Integration tests for the Language Translator V3 Service 9 | class LanguageTranslatorV3Test < Minitest::Test 10 | include Minitest::Hooks 11 | attr_accessor :service 12 | def before_all 13 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 14 | apikey: ENV["LANGUAGE_TRANSLATOR_APIKEY"] 15 | ) 16 | @service = IBMWatson::LanguageTranslatorV3.new( 17 | authenticator: authenticator, 18 | url: ENV["LANGUAGE_TRANSLATOR_URL"], 19 | version: "2018-05-01" 20 | ) 21 | @service.add_default_headers( 22 | headers: { 23 | "X-Watson-Test" => "1" 24 | } 25 | ) 26 | end 27 | 28 | def test_get_model 29 | service_response = service.get_model( 30 | model_id: "en-it" 31 | ).result 32 | refute(service_response.nil?) 33 | end 34 | 35 | def test_list_models 36 | service_response = service.list_models.result 37 | refute(service_response.nil?) 38 | end 39 | 40 | def test_translate_source_target 41 | service_response = service.translate( 42 | text: "Hola, cómo estás? €", 43 | source: "es", 44 | target: "en" 45 | ).result 46 | refute(service_response.nil?) 47 | end 48 | 49 | def test_translate_model_id 50 | service_response = service.translate( 51 | text: "Messi is the best ever", 52 | model_id: "en-es" 53 | ).result 54 | refute(service_response.nil?) 55 | end 56 | 57 | def test_identify 58 | service_response = service.identify( 59 | text: "祝你有美好的一天" 60 | ).result 61 | refute(service_response.nil?) 62 | end 63 | 64 | def test_translate_document 65 | @service.add_default_headers( 66 | headers: { 67 | "X-Watson-Test" => "1" 68 | } 69 | ) 70 | 71 | File.open(Dir.getwd + "/resources/translation_doc.txt") do |file_info| 72 | service_response = service.translate_document( 73 | file: file_info, 74 | filename: "translation_doc.txt", 75 | model_id: "en-fr" 76 | ).result 77 | refute(service_response.nil?) 78 | end 79 | end 80 | 81 | def test_list_documents 82 | service_response = service.list_documents.result 83 | refute(service_response.nil?) 84 | end 85 | 86 | def test_list_identifiable_languages 87 | service_response = service.list_identifiable_languages.result 88 | refute(service_response.nil?) 89 | end 90 | 91 | def test_create_delete_model 92 | skip "Methods not available in lite plans" 93 | custom_model = File.open(Dir.getwd + "/resources/language_translator_model.tmx") 94 | service_response = service.create_model( 95 | base_model_id: "en-fr", 96 | name: "test_glossary_ruby_integration", 97 | forced_glossary: custom_model 98 | ).result 99 | refute(service_response.nil?) 100 | model_id = service_response["model_id"] 101 | service_response = service.delete_model( 102 | model_id: model_id 103 | ).result 104 | assert_equal("OK", service_response["status"]) 105 | end 106 | 107 | def test_list_languages 108 | service_response = service.list_languages.result 109 | refute(service_response.nil?) 110 | end 111 | end 112 | else 113 | class LanguageTranslatorV3Test < Minitest::Test 114 | def test_missing_credentials_skip_integration 115 | skip "Skip language translator integration tests because credentials have not been provided" 116 | end 117 | end 118 | end 119 | -------------------------------------------------------------------------------- /test/integration/test_natural_language_understanding_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("json") 4 | require_relative("./../test_helper.rb") 5 | 6 | if !ENV["NATURAL_LANGUAGE_UNDERSTANDING_APIKEY"].nil? && !ENV["NATURAL_LANGUAGE_UNDERSTANDING_URL"].nil? 7 | # Integration tests for the Natural Language Understanding V1 Service 8 | class NaturalLanguageUnderstandingV1Test < Minitest::Test 9 | include Minitest::Hooks 10 | attr_accessor :service 11 | def before_all 12 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 13 | apikey: ENV["NATURAL_LANGUAGE_UNDERSTANDING_APIKEY"] 14 | ) 15 | @service = IBMWatson::NaturalLanguageUnderstandingV1.new( 16 | version: "2018-03-16", 17 | authenticator: authenticator, 18 | url: ENV["NATURAL_LANGUAGE_UNDERSTANDING_URL"] 19 | ) 20 | @service.add_default_headers( 21 | headers: { 22 | "X-Watson-Learning-Opt-Out" => "1", 23 | "X-Watson-Test" => "1" 24 | } 25 | ) 26 | end 27 | 28 | def test_text_analyze 29 | service.add_default_headers( 30 | headers: { 31 | "X-Watson-Learning-Opt-Out" => "1", 32 | "X-Watson-Test" => "1" 33 | } 34 | ) 35 | text = "IBM is an American multinational technology company " 36 | text += "headquartered in Armonk, New York, United States, " 37 | text += "with operations in over 170 countries." 38 | service_response = service.analyze( 39 | features: { 40 | entities: { 41 | emotion: true, 42 | sentiment: true, 43 | limit: 2 44 | }, 45 | keywords: { 46 | emotion: true, 47 | sentiment: true, 48 | limit: 2 49 | } 50 | }, 51 | text: text 52 | ) 53 | assert((200..299).cover?(service_response.status)) 54 | end 55 | 56 | def test_html_analyze 57 | service.add_default_headers( 58 | headers: { 59 | "X-Watson-Learning-Opt-Out" => "1", 60 | "X-Watson-Test" => "1" 61 | } 62 | ) 63 | service_response = service.analyze( 64 | features: { 65 | sentiment: {} 66 | }, 67 | html: "hello this is a test " 68 | ) 69 | assert((200..299).cover?(service_response.status)) 70 | end 71 | 72 | def test_url_analyze 73 | service.add_default_headers( 74 | headers: { 75 | "X-Watson-Learning-Opt-Out" => "1", 76 | "X-Watson-Test" => "1" 77 | } 78 | ) 79 | service_response = service.analyze( 80 | features: { 81 | categories: {} 82 | }, 83 | url: "www.ibm.com" 84 | ) 85 | assert((200..299).cover?(service_response.status)) 86 | end 87 | 88 | def test_list_models 89 | # skip 90 | service.add_default_headers( 91 | headers: { 92 | "X-Watson-Learning-Opt-Out" => "1", 93 | "X-Watson-Test" => "1" 94 | } 95 | ) 96 | service_response = service.list_models 97 | assert((200..299).cover?(service_response.status)) 98 | end 99 | 100 | def test_check_orphands 101 | skip "Use to help delete old models" 102 | service.add_default_headers( 103 | headers: { 104 | "X-Watson-Learning-Opt-Out" => "1", 105 | "X-Watson-Test" => "1" 106 | } 107 | ) 108 | service_response = service.list_sentiment_models 109 | puts JSON.pretty_generate(service_response.result) 110 | service_response = service.list_categories_models 111 | puts JSON.pretty_generate(service_response.result) 112 | service_response = service.list_classifications_models 113 | puts JSON.pretty_generate(service_response.result) 114 | 115 | # service.delete_sentiment_model(model_id: "model_id1") 116 | # service.delete_categories_model(model_id: "0122b971-94c9-4468-a98f-930f4ce28c32") 117 | # service.delete_classifications_model(model_id: "0122b971-94c9-4468-a98f-930f4ce28c32") 118 | end 119 | 120 | def test_sentiment_models 121 | # skip "test_sentiment_models" 122 | service.add_default_headers( 123 | headers: { 124 | "X-Watson-Learning-Opt-Out" => "1", 125 | "X-Watson-Test" => "1" 126 | } 127 | ) 128 | training_data = File.open(Dir.getwd + "/resources/nlu_sentiment_data.csv") 129 | service_response = service.create_sentiment_model( 130 | language: "en", 131 | training_data: training_data 132 | ) 133 | assert((200..299).cover?(service_response.status)) 134 | 135 | service_response = service.list_sentiment_models 136 | model_id = service_response.result["models"][0]["model_id"] 137 | assert((200..299).cover?(service_response.status)) 138 | 139 | service_response = service.get_sentiment_model(model_id: model_id) 140 | assert((200..299).cover?(service_response.status)) 141 | 142 | service_response = service.update_sentiment_model( 143 | model_id: model_id, 144 | language: "en", 145 | training_data: training_data 146 | ) 147 | assert((200..299).cover?(service_response.status)) 148 | 149 | service_response = service.delete_sentiment_model( 150 | model_id: model_id 151 | ) 152 | assert((200..299).cover?(service_response.status)) 153 | end 154 | 155 | def test_categories_models 156 | # skip "test_categories_models" 157 | service.add_default_headers( 158 | headers: { 159 | "X-Watson-Learning-Opt-Out" => "1", 160 | "X-Watson-Test" => "1" 161 | } 162 | ) 163 | training_data = File.open(Dir.getwd + "/resources/nlu_categories_training.json") 164 | service_response = service.create_categories_model( 165 | language: "en", 166 | training_data: training_data, 167 | training_data_content_type: "application/json" 168 | ) 169 | assert((200..299).cover?(service_response.status)) 170 | 171 | service_response = service.list_categories_models 172 | model_id = service_response.result["models"][0]["model_id"] 173 | assert((200..299).cover?(service_response.status)) 174 | # puts JSON.pretty_generate(service_response.result) 175 | # puts JSON.pretty_generate(model_id) 176 | 177 | service_response = service.get_categories_model(model_id: model_id) 178 | assert((200..299).cover?(service_response.status)) 179 | 180 | service_response = service.update_categories_model( 181 | model_id: model_id, 182 | language: "en", 183 | training_data: training_data, 184 | training_data_content_type: "application/json" 185 | ) 186 | assert((200..299).cover?(service_response.status)) 187 | 188 | service_response = service.delete_categories_model( 189 | model_id: model_id 190 | ) 191 | assert((200..299).cover?(service_response.status)) 192 | end 193 | 194 | def test_classifications_models 195 | # skip "test_classifications_models" 196 | service.add_default_headers( 197 | headers: { 198 | "X-Watson-Learning-Opt-Out" => "1", 199 | "X-Watson-Test" => "1" 200 | } 201 | ) 202 | training_data = File.open(Dir.getwd + "/resources/nlu_classifications_training.json") 203 | service_response = service.create_classifications_model( 204 | language: "en", 205 | training_data: training_data, 206 | training_data_content_type: "application/json" 207 | ) 208 | assert((200..299).cover?(service_response.status)) 209 | 210 | service_response = service.list_classifications_models 211 | model_id = service_response.result["models"][0]["model_id"] 212 | assert((200..299).cover?(service_response.status)) 213 | # puts JSON.pretty_generate(service_response.result) 214 | # puts JSON.pretty_generate(model_id) 215 | 216 | service_response = service.get_classifications_model(model_id: model_id) 217 | assert((200..299).cover?(service_response.status)) 218 | 219 | service_response = service.update_classifications_model( 220 | model_id: model_id, 221 | language: "en", 222 | training_data: training_data, 223 | training_data_content_type: "application/json" 224 | ) 225 | assert((200..299).cover?(service_response.status)) 226 | 227 | service_response = service.delete_classifications_model( 228 | model_id: model_id 229 | ) 230 | assert((200..299).cover?(service_response.status)) 231 | end 232 | end 233 | else 234 | class NaturalLanguageUnderstandingV1Test < Minitest::Test 235 | def test_missing_credentials_skip_integration 236 | skip "Skip natural language understanding integration tests because credentials have not been provided" 237 | end 238 | end 239 | end 240 | -------------------------------------------------------------------------------- /test/integration/test_speech_to_text_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative("./../test_helper.rb") 4 | require_relative("./../../lib/ibm_watson/websocket/recognize_callback.rb") 5 | require_relative("./../../lib/ibm_watson/websocket/speech_to_text_websocket_listener.rb") 6 | require("minitest/hooks/test") 7 | require("concurrent") 8 | 9 | # Recognize Callback class 10 | class MyRecognizeCallback < IBMWatson::RecognizeCallback 11 | def initialize(atomic_boolean: nil) 12 | super 13 | @atomic_boolean = atomic_boolean 14 | end 15 | 16 | def on_error(*) 17 | @atomic_boolean.make_true 18 | end 19 | 20 | def on_inactivity_timeout(*) 21 | @atomic_boolean.make_true 22 | end 23 | end 24 | 25 | if !ENV["SPEECH_TO_TEXT_APIKEY"].nil? && !ENV["SPEECH_TO_TEXT_URL"].nil? 26 | # Integration tests for the Speech to Text V1 Service 27 | class SpeechToTextV1Test < Minitest::Test 28 | include Minitest::Hooks 29 | attr_accessor :service 30 | def before_all 31 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 32 | apikey: ENV["SPEECH_TO_TEXT_APIKEY"] 33 | ) 34 | @service = IBMWatson::SpeechToTextV1.new( 35 | url: ENV["SPEECH_TO_TEXT_URL"], 36 | authenticator: authenticator 37 | ) 38 | @service.add_default_headers( 39 | headers: { 40 | "X-Watson-Learning-Opt-Out" => "1", 41 | "X-Watson-Test" => "1" 42 | } 43 | ) 44 | end 45 | 46 | def test_models 47 | output = @service.list_models.result 48 | refute_nil(output) 49 | 50 | model = @service.get_model( 51 | model_id: "ko-KR_BroadbandModel" 52 | ).result 53 | model = model 54 | refute_nil(model) 55 | 56 | begin 57 | @service.get_model( 58 | model_id: "bogus" 59 | ) 60 | rescue StandardError => e 61 | refute_nil(e.error) 62 | end 63 | end 64 | 65 | def test_recognize_await 66 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 67 | future = @service.await.recognize( 68 | audio: audio_file, 69 | content_type: "audio/l16; rate=44100" 70 | ) 71 | output = future.value.result 72 | refute_nil(output["results"][0]["alternatives"][0]["transcript"]) 73 | end 74 | 75 | def test_recognize_with_keywords 76 | file = File.open(Dir.getwd + "/resources/speech.wav") 77 | File.open(file) do |audio_file| 78 | output = @service.recognize( 79 | audio: audio_file, 80 | content_type: "audio/l16; rate=44100", 81 | timestamps: true, 82 | word_alternatives_threshold: 0.9, 83 | keywords: %w[colorado tornado], 84 | keywords_threshold: 0.5 85 | ) 86 | refute_nil(output.result["results"][0]["alternatives"][0]["transcript"]) 87 | end 88 | end 89 | 90 | def test_recognize_with_single_keyword 91 | file = File.open(Dir.getwd + "/resources/sound-with-pause.wav") 92 | output = nil 93 | File.open(file) do |audio_file| 94 | output = @service.recognize( 95 | audio: audio_file, 96 | content_type: "audio/l16; rate=44100", 97 | timestamps: true, 98 | word_alternatives_threshold: 0.9, 99 | keywords: %w"[colorado]", 100 | keywords_threshold: 0.5, 101 | split_transcript_at_phrase_end: true, 102 | end_of_phrase_silence_time: nil 103 | ) 104 | refute_nil(output.result["results"][0]["alternatives"][0]["transcript"]) 105 | assert(3, output.result["results"].length) 106 | end 107 | end 108 | 109 | def test_recognize_async 110 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 111 | future = @service.async.recognize( 112 | audio: audio_file, 113 | content_type: "audio/l16; rate=44100" 114 | ) 115 | future.wait! 116 | output = future.value.result 117 | refute_nil(output["results"][0]["alternatives"][0]["transcript"]) 118 | end 119 | 120 | def test_recognitions 121 | skip "Skip because of timeouts" 122 | output = @service.check_jobs.result 123 | refute_nil(output) 124 | end 125 | 126 | def test_custom_corpora 127 | skip "Skip to allow for concurrent travis jobs" 128 | model = @service.create_language_model( 129 | name: "integration_test_model", 130 | base_model_name: "en-US_BroadbandModel" 131 | ).result 132 | customization_id = model["customization_id"] 133 | 134 | output = @service.list_corpora( 135 | customization_id: customization_id 136 | ).result 137 | refute_nil(output) 138 | 139 | @service.delete_language_model( 140 | customization_id: customization_id 141 | ) 142 | end 143 | 144 | def test_acoustic_model 145 | list_models = @service.list_acoustic_models.result 146 | refute_nil(list_models) 147 | 148 | skip "Skip to allow for concurrent travis jobs" 149 | create_acoustic_model = @service.create_acoustic_model( 150 | name: "integration_test_model_ruby", 151 | base_model_name: "en-US_BroadbandModel" 152 | ).result 153 | refute_nil(create_acoustic_model) 154 | 155 | get_acoustic_model = @service.get_acoustic_model( 156 | customization_id: create_acoustic_model["customization_id"] 157 | ).result 158 | refute_nil(get_acoustic_model) 159 | 160 | @service.reset_acoustic_model( 161 | customization_id: get_acoustic_model["customization_id"] 162 | ) 163 | 164 | @service.delete_acoustic_model( 165 | customization_id: get_acoustic_model["customization_id"] 166 | ) 167 | end 168 | 169 | def test_recognize_websocket_as_chunks 170 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 171 | atomic_boolean = Concurrent::AtomicBoolean.new 172 | mycallback = MyRecognizeCallback.new(atomic_boolean: atomic_boolean) 173 | speech = @service.recognize_using_websocket( 174 | chunk_data: true, 175 | recognize_callback: mycallback, 176 | interim_results: true, 177 | timestamps: true, 178 | max_alternatives: 2, 179 | word_alternatives_threshold: 0.5, 180 | content_type: "audio/wav" 181 | ) 182 | Thread.new do 183 | until audio_file.eof? 184 | chunk = audio_file.read(1024) 185 | speech.add_audio_chunk(chunk: chunk) 186 | end 187 | sleep(1) 188 | speech.stop_audio # Tell the websocket object that no more audio will be added 189 | end 190 | thr = Thread.new { speech.start } 191 | thr.join 192 | assert(atomic_boolean.false?) 193 | end 194 | 195 | def test_recognize_websocket 196 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 197 | atomic_boolean = Concurrent::AtomicBoolean.new 198 | mycallback = MyRecognizeCallback.new(atomic_boolean: atomic_boolean) 199 | speech = @service.recognize_using_websocket( 200 | audio: audio_file, 201 | recognize_callback: mycallback, 202 | interim_results: true, 203 | timestamps: true, 204 | max_alternatives: 2, 205 | word_alternatives_threshold: 0.5, 206 | content_type: "audio/wav" 207 | ) 208 | thr = Thread.new { speech.start } 209 | thr.join 210 | assert(atomic_boolean.false?) 211 | end 212 | 213 | def test_inactivity_timeout_using_websocket 214 | audio_file = File.open(Dir.getwd + "/resources/sound-with-pause.wav") 215 | atomic_boolean = Concurrent::AtomicBoolean.new 216 | mycallback = MyRecognizeCallback.new(atomic_boolean: atomic_boolean) 217 | speech = @service.recognize_using_websocket( 218 | audio: audio_file, 219 | recognize_callback: mycallback, 220 | interim_results: true, 221 | inactivity_timeout: 3, 222 | timestamps: true, 223 | max_alternatives: 2, 224 | word_alternatives_threshold: 0.5, 225 | content_type: "audio/wav" 226 | ) 227 | thr = Thread.new { speech.start } 228 | thr.join 229 | assert(atomic_boolean.true?) 230 | end 231 | 232 | def test_broken_audio_using_websocket 233 | audio_file = File.open(Dir.getwd + "/resources/car.jpg") 234 | atomic_boolean = Concurrent::AtomicBoolean.new 235 | mycallback = MyRecognizeCallback.new(atomic_boolean: atomic_boolean) 236 | speech = @service.recognize_using_websocket( 237 | audio: audio_file, 238 | recognize_callback: mycallback, 239 | interim_results: true, 240 | timestamps: true, 241 | max_alternatives: 2, 242 | word_alternatives_threshold: 0.5, 243 | content_type: "audio/wav" 244 | ) 245 | thr = Thread.new { speech.start } 246 | thr.join 247 | assert(atomic_boolean.true?) 248 | end 249 | 250 | def test_invalid_auth_using_websocket 251 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 252 | atomic_boolean = Concurrent::AtomicBoolean.new 253 | mycallback = MyRecognizeCallback.new(atomic_boolean: atomic_boolean) 254 | authenticator = IBMWatson::Authenticators::BearerTokenAuthenticator.new( 255 | bearer_token: "bogus_iam_access_token" 256 | ) 257 | temp_service = IBMWatson::SpeechToTextV1.new( 258 | authenticator: authenticator 259 | ) 260 | temp_service.add_default_headers( 261 | headers: { 262 | "X-Watson-Learning-Opt-Out" => "1", 263 | "X-Watson-Test" => "1" 264 | } 265 | ) 266 | speech = temp_service.recognize_using_websocket( 267 | audio: audio_file, 268 | recognize_callback: mycallback, 269 | interim_results: true, 270 | timestamps: true, 271 | max_alternatives: 2, 272 | word_alternatives_threshold: 0.5, 273 | content_type: "audio/wav" 274 | ) 275 | thr = Thread.new { speech.start } 276 | thr.join 277 | assert(atomic_boolean.true?) 278 | end 279 | 280 | def test_add_word 281 | model = @service.create_language_model( 282 | name: "integration_test_model", 283 | base_model_name: "en-US_BroadbandModel" 284 | ).result 285 | customization_id = model["customization_id"] 286 | service_response = @service.add_word( 287 | customization_id: customization_id, 288 | word_name: "IEEE", 289 | sounds_like: ["i triple e"], 290 | display_as: "IEEE" 291 | ) 292 | assert_nil(service_response) 293 | @service.delete_language_model( 294 | customization_id: customization_id 295 | ) 296 | end 297 | 298 | def test_add_word_double 299 | model = @service.create_language_model( 300 | name: "integration_test_model", 301 | base_model_name: "en-US_BroadbandModel" 302 | ).result 303 | customization_id = model["customization_id"] 304 | service_response = @service.add_word( 305 | customization_id: customization_id, 306 | word_name: "ABC" 307 | ) 308 | assert_nil(service_response) 309 | service_response = @service.get_word( 310 | customization_id: customization_id, 311 | word_name: "ABC" 312 | ) 313 | refute_nil(service_response) 314 | @service.delete_language_model( 315 | customization_id: customization_id 316 | ) 317 | end 318 | end 319 | else 320 | class SpeechToTextV1Test < Minitest::Test 321 | def test_missing_credentials_skip_integration 322 | skip "Skip speech to text integration tests because credentials have not been provided" 323 | end 324 | end 325 | end 326 | -------------------------------------------------------------------------------- /test/integration/test_text_to_speech_v1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative("./../test_helper.rb") 4 | require("minitest/hooks/test") 5 | 6 | if !ENV["TEXT_TO_SPEECH_APIKEY"].nil? && !ENV["TEXT_TO_SPEECH_URL"].nil? 7 | # Integration tests for the Text to Speech V1 Service 8 | class TextToSpeechV1Test < Minitest::Test 9 | include Minitest::Hooks 10 | attr_accessor :service 11 | def before_all 12 | authenticator = IBMWatson::Authenticators::IamAuthenticator.new( 13 | apikey: ENV["TEXT_TO_SPEECH_APIKEY"] 14 | ) 15 | @service = IBMWatson::TextToSpeechV1.new( 16 | url: ENV["TEXT_TO_SPEECH_URL"], 17 | authenticator: authenticator 18 | ) 19 | @service.add_default_headers( 20 | headers: { 21 | "X-Watson-Learning-Opt-Out" => "1", 22 | "X-Watson-Test" => "1" 23 | } 24 | ) 25 | end 26 | 27 | def test_voices 28 | output = @service.list_voices.result 29 | refute(output["voices"].nil?) 30 | voice = @service.get_voice(voice: output["voices"][0]["name"]) 31 | refute(voice.nil?) 32 | end 33 | 34 | def test_speak 35 | output = @service.synthesize( 36 | text: "my voice is my passport", 37 | accept: "audio/wav", 38 | voice: "en-US_AllisonVoice" 39 | ).result 40 | refute(output.nil?) 41 | end 42 | 43 | def test_pronunciation 44 | output = @service.get_pronunciation( 45 | text: "hello" 46 | ).result 47 | refute(output["pronunciation"].nil?) 48 | end 49 | 50 | def test_customizations 51 | service_response = @service.list_custom_models 52 | refute(service_response.nil?) 53 | end 54 | 55 | def test_custom_words 56 | skip "Skip to allow for concurrent travis jobs" 57 | customization_id = @service.create_custom_model( 58 | name: "test_integration_customization", 59 | description: "customization for tests" 60 | ).result["customization_id"] 61 | words = @service.list_words(customization_id: customization_id).result["words"] 62 | assert(words.length.zero?) 63 | @service.add_word( 64 | customization_id: customization_id, 65 | word: "ACLs", 66 | translation: "ackles" 67 | ) 68 | words = [{ "word" => "MACLs", "translation" => "mackles" }] 69 | @service.add_words( 70 | customization_id: customization_id, 71 | words: words 72 | ) 73 | @service.delete_word( 74 | customization_id: customization_id, 75 | word: "ACLs" 76 | ) 77 | word = @service.get_word( 78 | customization_id: customization_id, 79 | word: "MACLs" 80 | ).result 81 | assert(word["translation"] == "mackles") 82 | @service.delete_custom_model( 83 | customization_id: customization_id 84 | ) 85 | end 86 | 87 | def test_custom_prompts 88 | customization_id = @service.create_custom_model( 89 | name: "test_integration_customization", 90 | description: "RUBY customization for tests" 91 | ).result["customization_id"] 92 | 93 | prompt_metadata = { prompt_text: "Thank you and goodbye" } 94 | prompt_json = JSON[prompt_metadata] 95 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 96 | prompt = @service.add_custom_prompt( 97 | customization_id: customization_id, 98 | prompt_id: "rubyprompt_id", 99 | metadata: prompt_json, 100 | file: audio_file 101 | ).result["prompt"] 102 | assert(prompt == "Thank you and goodbye") 103 | 104 | prompts = @service.list_custom_prompts(customization_id: customization_id).result["prompts"] 105 | refute(prompts.nil?) 106 | 107 | prompt = @service.get_custom_prompt( 108 | customization_id: customization_id, 109 | prompt_id: "rubyprompt_id" 110 | ).result["prompt"] 111 | assert(prompt == "Thank you and goodbye") 112 | 113 | @service.delete_custom_prompt( 114 | customization_id: customization_id, 115 | prompt_id: "rubyprompt_id" 116 | ) 117 | 118 | @service.delete_custom_model( 119 | customization_id: customization_id 120 | ) 121 | end 122 | 123 | def test_speaker_models 124 | audio_file = File.open(Dir.getwd + "/resources/speech.wav") 125 | @service.create_speaker_model( 126 | speaker_name: "RubyMike", 127 | audio: audio_file 128 | ).result["speaker_model"] 129 | 130 | speakers = @service.list_speaker_models.result["speakers"] 131 | speaker_id = speakers[0]["speaker_id"] 132 | # puts JSON.pretty_generate(speakers) 133 | 134 | @service.get_speaker_model( 135 | speaker_id: speaker_id 136 | ).result["models_speaker"] 137 | 138 | # speaker_id = d3d03b69-4035-4420-928d-7ac2e0249829 139 | @service.delete_speaker_model( 140 | speaker_id: speaker_id 141 | ) 142 | end 143 | end 144 | else 145 | class TextToSpeechV1Test < Minitest::Test 146 | def test_missing_credentials_skip_integration 147 | skip "Skip text to speech integration tests because credentials have not been provided" 148 | end 149 | end 150 | end 151 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("simplecov") 4 | require("codecov") 5 | require("minitest/reporters") 6 | 7 | if ENV["COVERAGE"] 8 | SimpleCov.formatter = SimpleCov::Formatter::Codecov if ENV["CI"] 9 | unless SimpleCov.running 10 | SimpleCov.start do 11 | add_filter "/test/" 12 | add_filter do |src_file| 13 | File.basename(src_file.filename) == "version.rb" 14 | end 15 | 16 | command_name "Minitest" 17 | end 18 | end 19 | end 20 | 21 | require("minitest/autorun") 22 | require_relative("./../lib/ibm_watson.rb") 23 | require("minitest/retry") 24 | require("minitest/hooks/test") 25 | require("ibm_cloud_sdk_core") 26 | 27 | Minitest::Retry.use! 28 | 29 | Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true, slow_count: 10), Minitest::Reporters::SpecReporter.new, Minitest::Reporters::HtmlReporter.new] if ENV["CI"].nil? 30 | Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true, slow_count: 10), Minitest::Reporters::SpecReporter.new] if ENV["CI"] 31 | -------------------------------------------------------------------------------- /test/unit/test_assistant_v2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("json") 4 | require_relative("./../test_helper.rb") 5 | require("webmock/minitest") 6 | SimpleCov.command_name "test:unit" 7 | 8 | WebMock.disable_net_connect!(allow_localhost: true) 9 | 10 | # Unit tests for the Watson Assistant V1 Service 11 | class AssistantV2Test < Minitest::Test 12 | include Minitest::Hooks 13 | attr_accessor :service 14 | def before_all 15 | authenticator = IBMWatson::Authenticators::NoAuthAuthenticator.new 16 | @service = IBMWatson::AssistantV2.new( 17 | version: "2018-02-16", 18 | authenticator: authenticator 19 | ) 20 | end 21 | 22 | def test_message 23 | # service.set_default_headers("x-watson-learning-opt-out" => true) 24 | assistant_id = "f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec" 25 | session_id = "session" 26 | message_response = { 27 | "context" => { 28 | "conversation_id" => "1b7b67c0-90ed-45dc-8508-9488bc483d5b", 29 | "system" => { 30 | "dialog_stack" => ["root"], 31 | "dialog_turn_counter" => 1, 32 | "dialog_request_counter" => 1 33 | } 34 | }, 35 | "intents" => [], 36 | "entities" => [], 37 | "input" => {}, 38 | "output" => { 39 | "text" => "okay", 40 | "log_messages" => [] 41 | } 42 | } 43 | headers = { 44 | "Content-Type" => "application/json" 45 | } 46 | stub_request(:post, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/assistants/f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec/sessions/session/message?version=2018-02-16") 47 | .with( 48 | body: "{\"input\":{\"text\":\"Turn on the lights\"}}", 49 | headers: { 50 | "Accept" => "application/json", 51 | "Content-Type" => "application/json", 52 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 53 | } 54 | ).to_return(status: 200, body: message_response.to_json, headers: headers) 55 | service_response = service.message( 56 | assistant_id: assistant_id, 57 | session_id: session_id, 58 | input: { "text" => "Turn on the lights" }, 59 | context: nil 60 | ) 61 | assert_equal(message_response, service_response.result) 62 | 63 | message_ctx = { 64 | "context" => { 65 | "conversation_id" => "1b7b67c0-90ed-45dc-8508-9488bc483d5b", 66 | "system" => { 67 | "dialog_stack" => ["root"], 68 | "dialog_turn_counter" => 2, 69 | "dialog_request_counter" => 1 70 | } 71 | } 72 | } 73 | stub_request(:post, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/assistants/f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec/sessions/session/message?version=2018-02-16") 74 | .with( 75 | body: "{\"input\":{\"text\":\"Turn on the lights\"},\"context\":\"{\\\"conversation_id\\\":\\\"1b7b67c0-90ed-45dc-8508-9488bc483d5b\\\",\\\"system\\\":{\\\"dialog_stack\\\":[\\\"root\\\"],\\\"dialog_turn_counter\\\":2,\\\"dialog_request_counter\\\":1}}\"}", 76 | headers: { 77 | "Accept" => "application/json", 78 | "Content-Type" => "application/json", 79 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 80 | } 81 | ).to_return(status: 200, body: message_response.to_json, headers: headers) 82 | service_response = service.message( 83 | assistant_id: assistant_id, 84 | session_id: session_id, 85 | input: { "text" => "Turn on the lights" }, 86 | context: message_ctx["context"].to_json 87 | ) 88 | assert_equal(message_response, service_response.result) 89 | end 90 | 91 | def test_create_session 92 | # response = { 93 | # "name" => "Pizza app", 94 | # "created" => "2015-12-06T23:53:59.153Z", 95 | # "language" => "en", 96 | # "metadata" => {}, 97 | # "updated" => "2015-12-06T23:53:59.153Z", 98 | # "description" => "Pizza app", 99 | # "assistant_id" => "pizza_app-e0f3" 100 | # } 101 | # headers = { 102 | # "Content-Type" => "application/json" 103 | # } 104 | stub_request(:post, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/assistants/pizza_app-e0f3/sessions?version=2018-02-16") 105 | .with( 106 | headers: { 107 | "Accept" => "application/json", 108 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 109 | } 110 | ).to_return(status: 200, body: "", headers: {}) 111 | service_response = service.create_session( 112 | assistant_id: "pizza_app-e0f3" 113 | ) 114 | assert_equal("", service_response.result) 115 | end 116 | 117 | def test_delete_session 118 | stub_request(:delete, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/assistants/pizza_app-e0f3/sessions/session?version=2018-02-16") 119 | .with( 120 | headers: { 121 | "Accept" => "application/json", 122 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 123 | } 124 | ).to_return(status: 200, body: "", headers: {}) 125 | service_response = service.delete_session( 126 | assistant_id: "pizza_app-e0f3", 127 | session_id: "session" 128 | ) 129 | assert_nil(service_response) 130 | end 131 | 132 | def test_message_stateless 133 | # service.set_default_headers("x-watson-learning-opt-out" => true) 134 | assistant_id = "f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec" 135 | message_response = { 136 | "context" => { 137 | "conversation_id" => "1b7b67c0-90ed-45dc-8508-9488bc483d5b", 138 | "system" => { 139 | "dialog_stack" => ["root"], 140 | "dialog_turn_counter" => 1, 141 | "dialog_request_counter" => 1 142 | } 143 | }, 144 | "intents" => [], 145 | "entities" => [], 146 | "input" => {}, 147 | "output" => { 148 | "text" => "okay", 149 | "log_messages" => [] 150 | } 151 | } 152 | headers = { 153 | "Content-Type" => "application/json" 154 | } 155 | stub_request(:post, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/assistants/f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec/message?version=2018-02-16") 156 | .with( 157 | body: "{\"input\":{\"text\":\"Turn on the lights\"}}", 158 | headers: { 159 | "Accept" => "application/json", 160 | "Content-Type" => "application/json", 161 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 162 | } 163 | ).to_return(status: 200, body: message_response.to_json, headers: headers) 164 | service_response = service.message_stateless( 165 | assistant_id: assistant_id, 166 | input: { "text" => "Turn on the lights" }, 167 | context: nil 168 | ) 169 | assert_equal(message_response, service_response.result) 170 | 171 | message_ctx = { 172 | "context" => { 173 | "conversation_id" => "1b7b67c0-90ed-45dc-8508-9488bc483d5b", 174 | "system" => { 175 | "dialog_stack" => ["root"], 176 | "dialog_turn_counter" => 2, 177 | "dialog_request_counter" => 1 178 | } 179 | } 180 | } 181 | stub_request(:post, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/assistants/f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec/message?version=2018-02-16") 182 | .with( 183 | body: "{\"input\":{\"text\":\"Turn on the lights\"},\"context\":\"{\\\"conversation_id\\\":\\\"1b7b67c0-90ed-45dc-8508-9488bc483d5b\\\",\\\"system\\\":{\\\"dialog_stack\\\":[\\\"root\\\"],\\\"dialog_turn_counter\\\":2,\\\"dialog_request_counter\\\":1}}\"}", 184 | headers: { 185 | "Accept" => "application/json", 186 | "Content-Type" => "application/json", 187 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 188 | } 189 | ).to_return(status: 200, body: message_response.to_json, headers: headers) 190 | service_response = service.message_stateless( 191 | assistant_id: assistant_id, 192 | input: { "text" => "Turn on the lights" }, 193 | context: message_ctx["context"].to_json 194 | ) 195 | assert_equal(message_response, service_response.result) 196 | end 197 | 198 | def test_list_logs 199 | stub_request(:get, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/assistants/pizza_app-e0f3/logs?version=2018-02-16") 200 | .with( 201 | headers: { 202 | "Accept" => "application/json", 203 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 204 | } 205 | ).to_return(status: 200, body: "", headers: {}) 206 | service_response = service.list_logs( 207 | assistant_id: "pizza_app-e0f3" 208 | ) 209 | assert_equal("", service_response.result) 210 | end 211 | 212 | def test_delete_user_data 213 | stub_request(:delete, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/user_data?customer_id=pizza_app-e0f3&version=2018-02-16") 214 | .with( 215 | headers: { 216 | "Accept" => "application/json", 217 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 218 | } 219 | ).to_return(status: 200, body: "", headers: {}) 220 | service_response = service.delete_user_data( 221 | customer_id: "pizza_app-e0f3" 222 | ) 223 | assert_nil(service_response) 224 | end 225 | 226 | def test_bulk_classify 227 | skill_id = "f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec" 228 | message_response = { 229 | "context" => { 230 | "conversation_id" => "1b7b67c0-90ed-45dc-8508-9488bc483d5b", 231 | "system" => { 232 | "dialog_stack" => ["root"], 233 | "dialog_turn_counter" => 1, 234 | "dialog_request_counter" => 1 235 | } 236 | }, 237 | "intents" => [], 238 | "entities" => [], 239 | "input" => {}, 240 | "output" => { 241 | "text" => "okay", 242 | "log_messages" => [] 243 | } 244 | } 245 | headers = { 246 | "Content-Type" => "application/json" 247 | } 248 | stub_request(:post, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/skills/f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec/workspace/bulk_classify?version=2018-02-16") 249 | .with( 250 | body: "{\"input\":{\"text\":\"Turn on the lights\"}}", 251 | headers: { 252 | "Accept" => "application/json", 253 | "Content-Type" => "application/json", 254 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 255 | } 256 | ).to_return(status: 200, body: message_response.to_json, headers: headers) 257 | service_response = service.bulk_classify( 258 | skill_id: skill_id, 259 | input: { "text" => "Turn on the lights" } 260 | ) 261 | assert_equal(message_response, service_response.result) 262 | 263 | stub_request(:post, "https://api.us-south.assistant.watson.cloud.ibm.com/v2/skills/f8fdbc65-e0bd-4e43-b9f8-2975a366d4ec/workspace/bulk_classify?version=2018-02-16") 264 | .with( 265 | headers: { 266 | "Accept" => "application/json", 267 | "Content-Type" => "application/json", 268 | "Host" => "api.us-south.assistant.watson.cloud.ibm.com" 269 | } 270 | ).to_return(status: 200, body: message_response.to_json, headers: headers) 271 | service_response = service.bulk_classify( 272 | skill_id: skill_id 273 | ) 274 | assert_equal(message_response, service_response.result) 275 | end 276 | end 277 | -------------------------------------------------------------------------------- /test/unit/test_configure_http_client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require("json") 4 | require_relative("./../test_helper.rb") 5 | require("webmock/minitest") 6 | 7 | WebMock.disable_net_connect!(allow_localhost: true) 8 | 9 | # Unit tests for the configure_http_client customizations, such as proxies and timeouts 10 | class HTTPConfigTest < Minitest::Test 11 | def test_proxy_address_port 12 | authenticator = IBMWatson::Authenticators::BearerTokenAuthenticator.new( 13 | bearer_token: "token" 14 | ) 15 | service = IBMWatson::NaturalLanguageUnderstandingV1.new( 16 | version: "2018-03-16", 17 | authenticator: authenticator 18 | ) 19 | service.configure_http_client( 20 | proxy: { 21 | address: "bogus_address.com", 22 | port: 9999 23 | } 24 | ) 25 | proxy = service.conn.default_options.proxy 26 | assert_equal("bogus_address.com", proxy[:proxy_address]) 27 | assert_equal(9999, proxy[:proxy_port]) 28 | end 29 | 30 | def test_proxy_username_password 31 | authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 32 | username: "username", 33 | password: "password" 34 | ) 35 | 36 | service = IBMWatson::NaturalLanguageUnderstandingV1.new( 37 | version: "2018-03-16", 38 | authenticator: authenticator 39 | ) 40 | service.configure_http_client( 41 | proxy: { 42 | address: "bogus_address.com", 43 | port: 9999, 44 | username: "username", 45 | password: "password" 46 | } 47 | ) 48 | proxy = service.conn.default_options.proxy 49 | assert_equal("bogus_address.com", proxy[:proxy_address]) 50 | assert_equal(9999, proxy[:proxy_port]) 51 | assert_equal("username", proxy[:proxy_username]) 52 | assert_equal("password", proxy[:proxy_password]) 53 | end 54 | 55 | def test_proxy_headers 56 | authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 57 | username: "username", 58 | password: "password" 59 | ) 60 | 61 | service = IBMWatson::NaturalLanguageUnderstandingV1.new( 62 | version: "2018-03-16", 63 | authenticator: authenticator 64 | ) 65 | service.configure_http_client( 66 | proxy: { 67 | address: "bogus_address.com", 68 | port: 9999, 69 | headers: { 70 | bogus_header: true 71 | } 72 | } 73 | ) 74 | proxy = service.conn.default_options.proxy 75 | assert_equal("bogus_address.com", proxy[:proxy_address]) 76 | assert_equal(9999, proxy[:proxy_port]) 77 | assert_equal({ bogus_header: true }, proxy[:proxy_headers]) 78 | end 79 | 80 | def test_proxy_username_password_headers 81 | authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 82 | username: "username", 83 | password: "password" 84 | ) 85 | 86 | service = IBMWatson::NaturalLanguageUnderstandingV1.new( 87 | version: "2018-03-16", 88 | authenticator: authenticator 89 | ) 90 | service.configure_http_client( 91 | proxy: { 92 | address: "bogus_address.com", 93 | port: 9999, 94 | username: "username", 95 | password: "password", 96 | headers: { 97 | bogus_header: true 98 | } 99 | } 100 | ) 101 | proxy = service.conn.default_options.proxy 102 | assert_equal("bogus_address.com", proxy[:proxy_address]) 103 | assert_equal(9999, proxy[:proxy_port]) 104 | assert_equal("username", proxy[:proxy_username]) 105 | assert_equal("password", proxy[:proxy_password]) 106 | assert_equal({ bogus_header: true }, proxy[:proxy_headers]) 107 | end 108 | 109 | def test_timeout_per_operation 110 | authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 111 | username: "username", 112 | password: "password" 113 | ) 114 | 115 | service = IBMWatson::NaturalLanguageUnderstandingV1.new( 116 | version: "2018-03-16", 117 | authenticator: authenticator 118 | ) 119 | service.configure_http_client( 120 | timeout: { 121 | per_operation: { 122 | read: 5, 123 | write: 7, 124 | connect: 10 125 | } 126 | } 127 | ) 128 | timeout_class = service.conn.default_options.timeout_class 129 | assert_equal(HTTP::Timeout::PerOperation, timeout_class) 130 | 131 | expected_timeouts = { 132 | read_timeout: 5, 133 | write_timeout: 7, 134 | connect_timeout: 10 135 | } 136 | timeout = service.conn.default_options.timeout_options 137 | assert_equal(expected_timeouts, timeout) 138 | end 139 | 140 | def test_timeout_global 141 | authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 142 | username: "username", 143 | password: "password" 144 | ) 145 | 146 | service = IBMWatson::NaturalLanguageUnderstandingV1.new( 147 | version: "2018-03-16", 148 | authenticator: authenticator 149 | ) 150 | service.configure_http_client( 151 | timeout: { 152 | global: 20 153 | } 154 | ) 155 | timeout_class = service.conn.default_options.timeout_class 156 | assert_equal(HTTP::Timeout::Global, timeout_class) 157 | 158 | expected_timeouts = { 159 | global_timeout: 20 160 | } 161 | timeout = service.conn.default_options.timeout_options 162 | assert_equal(expected_timeouts, timeout) 163 | end 164 | 165 | def test_disable_ssl_verification 166 | authenticator = IBMWatson::Authenticators::BasicAuthenticator.new( 167 | username: "username", 168 | password: "password" 169 | ) 170 | 171 | service = IBMWatson::NaturalLanguageUnderstandingV1.new( 172 | version: "2018-03-16", 173 | authenticator: authenticator 174 | ) 175 | service.configure_http_client(disable_ssl_verification: true) 176 | refute_nil(service.conn.default_options.ssl_context) 177 | end 178 | end 179 | --------------------------------------------------------------------------------