-
Notifications
You must be signed in to change notification settings - Fork 64
feat: Support AI Extract endpoints #574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Support AI Extract endpoints #574
Conversation
Pull Request Test Coverage Report for Build 14999587544Details
💛 - Coveralls |
src/commands/ai/extract.js
Outdated
| 'Sends an AI request to supported LLMs and extracts metadata in the form of key value pairs'; | ||
| AiExtractCommand.examples = [ | ||
| 'box ai:extract --items=id=12345,type=file --prompt "firstName, lastName, location, yearOfBirth, company"', | ||
| 'box ai:extract --items=id=12345,type=file --prompt "firstName, lastName" --ai_agent="id=14031;type=ai_agent_extract;basic_text.llm_endpoint_params.type=openai_params;basic_text.llm_endpoint_params.frequency_penalty=1.5;basic_text.llm_endpoint_params.presence_penalty=1.5;basic_text.llm_endpoint_params.stop=<|im_end|>;basic_text.llm_endpoint_params.temperature=0;basic_text.llm_endpoint_params.top_p=1;basic_text.model=azure__openai__gpt_4o_mini;basic_text.num_tokens_for_completion=8400;basic_text.prompt_template=It is {current_date}, consider these travel options {content} and answer the {user_question}.;basic_text.system_message=You are a helpful travel assistant specialized in budget travel;long_text.embeddings.model=azure__openai__text_embedding_ada_002;long_text.embeddings.strategy.id=basic;long_text.embeddings.strategy.num_tokens_per_chunk=64;long_text.llm_endpoint_params.type=openai_params;long_text.llm_endpoint_params.frequency_penalty=1.5;long_text.llm_endpoint_params.presence_penalty=1.5;long_text.llm_endpoint_params.stop=<|im_end|>;long_text.llm_endpoint_params.temperature=0;long_text.llm_endpoint_params.top_p=1;long_text.model=azure__openai__gpt_4o_mini;long_text.num_tokens_for_completion=8400;long_text.prompt_template=It is {current_date}, consider these travel options {content} and answer the {user_question}.;long_text.system_message=You are a helpful travel assistant specialized in budget travel"', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the AI Agent should be a JSON object?
src/commands/ai/extract.js
Outdated
| }) | ||
| }; | ||
|
|
||
| module.exports = AiExtractCommand; No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alway keep newline at end of file
| }); | ||
| }); | ||
|
|
||
| describe('ai:extract-structured', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also need add another test with AI Agent including in the params
test/commands/ai.test.js
Outdated
| const assert = require('chai').assert; | ||
| const { TEST_API_ROOT, getFixture } = require('../helpers/test-helper'); | ||
| const {TEST_API_ROOT, getFixture} = require('../helpers/test-helper'); | ||
| const fs = require('fs'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove fs
| */ | ||
|
|
||
| function removeUndefinedValues(obj) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| FLAGS | ||
| -h, --help Show CLI help | ||
| -q, --quiet Suppress any non-error output to stderr | ||
| -s, --save Save report to default reports folder on disk | ||
| -t, --token=<value> Provide a token to perform this call | ||
| -v, --verbose Show verbose output, which can be helpful for debugging | ||
| -y, --yes Automatically respond yes to all confirmation prompts | ||
| --as-user=<value> Provide an ID for a user | ||
| --bulk-file-path=<value> File path to bulk .csv or .json objects | ||
| --csv Output formatted CSV | ||
| --fields=<value> Comma separated list of fields to show | ||
| --items=<value>... (required) The items for the AI request | ||
| --json Output formatted JSON | ||
| --no-color Turn off colors for logging | ||
| --prompt=<value> (required) The prompt for the AI request | ||
| --save-to-file-path=<value> Override default file path to save report |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why we don't have the AI Agent in this list of flag?
docs/ai.md
Outdated
|
|
||
| ``` | ||
| USAGE | ||
| $ box ai:extract --prompt <value> --items <value>... --ai_agent <value> [-t <value>] [--as-user <value>] [--no-color] [--json | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The flag ai_agent is inconsistent with other params, normally we use kebab case for flags, like no-color or as-user,...
congminh1254
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep this coding practice:
- Always newline at end of file.
- For comment, please have a spacing and uppercase for first character, like
// This is comment
but not
//this is comment
|
Please check the failing CI before asking for review PR |
congminh1254
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed some change about eslint, please pull before fixing your code.
| } | ||
| } | ||
|
|
||
| AiExtractStructuredCommand.description = 'Extract structured metadata from a file using Box AI'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description should reuse from Box API, like: "Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of key-value pairs."
| 'box ai:extract-structured --items="id=12345,type=file" --fields "key=firstName,type=string,description=Person first name,prompt=What is the first name?,displayName=First name" --fields "key=lastName,type=string,description=Person last name,prompt=What is the last name?,displayName=Last name" --ai-agent \'{"type":"ai_agent_extract","basicText":{"llmEndpointParams":{"type":"openai_params","frequencyPenalty": 1.5,"presencePenalty": 1.5,"stop": "<|im_end|>","temperature": 0,"topP": 1},"model": "azure__openai__gpt_4o_mini","numTokensForCompletion": 8400,"promptTemplate": "It is, consider these travel options and answer the.","systemMessage": "You are a helpful travel assistant specialized in budget travel"},"longText":{"embeddings":{ "model": "azure__openai__text_embedding_ada_002","strategy":{"id": "basic","numTokensPerChunk": 64}},"llmEndpointParams":{"type":"openai_params","frequencyPenalty": 1.5,"presencePenalty": 1.5,"stop": "<|im_end|>","temperature": 0,"topP": 1},"model":"azure__openai__gpt_4o_mini","numTokensForCompletion":8400,"promptTemplate":"It is , consider these travel options and answer the.","systemMessage":"You are a helpful travel assistant specialized in budget travel"}}\'', | ||
| 'box ai:extract-structured --items="id=12345,type=file" --metadata-template="type=metadata_template,scope=enterprise,template_key=test" --ai-agent \'{"type":"ai_agent_extract","basicText":{"llmEndpointParams":{"type":"openai_params","frequencyPenalty": 1.5,"presencePenalty": 1.5,"stop": "<|im_end|>","temperature": 0,"topP": 1},"model": "azure__openai__gpt_4o_mini","numTokensForCompletion": 8400,"promptTemplate": "It is, consider these travel options and answer the.","systemMessage": "You are a helpful travel assistant specialized in budget travel"},"longText":{"embeddings":{ "model": "azure__openai__text_embedding_ada_002","strategy":{"id": "basic","numTokensPerChunk": 64}},"llmEndpointParams":{"type":"openai_params","frequencyPenalty": 1.5,"presencePenalty": 1.5,"stop": "<|im_end|>","temperature": 0,"topP": 1},"model":"azure__openai__gpt_4o_mini","numTokensForCompletion":8400,"promptTemplate":"It is , consider these travel options and answer the.","systemMessage":"You are a helpful travel assistant specialized in budget travel"}}\'', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example is too complicated and hard to read, should only one example (without the AI Agent) or the second example can with the AI Agent but with a few main fields.
| }, | ||
| }), | ||
| 'metadata-template': Flags.string({ | ||
| description: 'metadata template to use for the AI request', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| fields: Flags.string({ | ||
| multiple: true, | ||
| description: | ||
| 'JSON string of fields to extract (e.g., [{"key":"firstName","type":"string","description":"Person first name","prompt":"What is the first name?","displayName":"First name"}])', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a JSON string
| const fields = { | ||
| key: '', | ||
| type: '', | ||
| description: '', | ||
| prompt: '', | ||
| displayName: '', | ||
| }; | ||
|
|
||
| const obj = utils.parseStringToObject(input, ['key', 'type', 'description', 'prompt', 'displayName']); | ||
| for (const key in obj) { | ||
| if (key === 'key') { | ||
| fields.key = obj[key]; | ||
| } else if (key === 'type') { | ||
| fields.type = obj[key]; | ||
| } else if (key === 'description') { | ||
| fields.description = obj[key]; | ||
| } else if (key === 'prompt') { | ||
| fields.prompt = obj[key]; | ||
| } else if (key === 'displayName') { | ||
| fields.displayName = obj[key]; | ||
| } else { | ||
| throw new Error(`Invalid item key ${key}`); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing options.
| }), | ||
| 'ai-agent': Flags.string({ | ||
| required: false, | ||
| description: 'The AI agent to be used for extraction (e.g., key=value pairs with semicolons or file:config.json)', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in key=value format
src/commands/ai/extract.js
Outdated
| ...BoxCommand.flags, | ||
| prompt: Flags.string({ | ||
| required: true, | ||
| description: 'The prompt for the AI request', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reuse description from Box API, but short version (should the first sentence, for example)
src/commands/ai/extract.js
Outdated
| }), | ||
| items: Flags.string({ | ||
| required: true, | ||
| description: 'The items for the AI request', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reuse description from Box API, but short version (should the first sentence, for example)
src/commands/ai/extract.js
Outdated
| }), | ||
| 'ai-agent': Flags.string({ | ||
| required: false, | ||
| description: 'The AI agent to be used for extraction', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should let user know it's in JSON format and can provide an simple example for this field
| AiExtractStructuredCommand.description = 'Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of key-value pairs. For this request, you either need a metadata template or a list of fields you want to extract. Input is either a metadata template or a list of fields to ensure the structure.'; | ||
| AiExtractStructuredCommand.examples = [ | ||
| 'box ai:extract-structured --items="id=12345,type=file" --fields "key=hobby,type=multiSelect,description=Person hobby,prompt=What is your hobby?,displayName=Hobby,options=Guitar;Books"', | ||
| 'box ai:extract-structured --items="id=12345,type=file" --fields "key=firstName,type=string,description=Person first name,prompt=What is the first name?,displayName=First name" --fields "key=lastName,type=string,description=Person last name,prompt=What is the last name?,displayName=Last name"', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this example
| AiExtractStructuredCommand.examples = [ | ||
| 'box ai:extract-structured --items="id=12345,type=file" --fields "key=hobby,type=multiSelect,description=Person hobby,prompt=What is your hobby?,displayName=Hobby,options=Guitar;Books"', | ||
| 'box ai:extract-structured --items="id=12345,type=file" --fields "key=firstName,type=string,description=Person first name,prompt=What is the first name?,displayName=First name" --fields "key=lastName,type=string,description=Person last name,prompt=What is the last name?,displayName=Last name"', | ||
| 'box ai:extract-structured --items="id=12345,type=file" --metadata-template="type=metadata_template,scope=enterprise,template_key=test" --ai-agent \'{"type":"ai_agent_extract_structured","basicText":{"llmEndpointParams":{"type":"openai_params","frequencyPenalty": 1.5,"presencePenalty": 1.5,"stop": "<|im_end|>","temperature": 0,"topP": 1},"model": "azure__openai__gpt_4o_mini","numTokensForCompletion": 8400,"promptTemplate": "It is, consider these travel options and answer the.","systemMessage": "You are a helpful travel assistant specialized in budget travel"},"longText":{"embeddings":{ "model": "azure__openai__text_embedding_ada_002","strategy":{"id": "basic","numTokensPerChunk": 64}},"llmEndpointParams":{"type":"openai_params","frequencyPenalty": 1.5,"presencePenalty": 1.5,"stop": "<|im_end|>","temperature": 0,"topP": 1},"model":"azure__openai__gpt_4o_mini","numTokensForCompletion":8400,"promptTemplate":"It is , consider these travel options and answer the.","systemMessage":"You are a helpful travel assistant specialized in budget travel"}}\'', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove long text
| multiple: true, | ||
| description: 'The fields to be extracted from the provided items.', | ||
| parse(input) { | ||
| const fields = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't assign empty string by default
src/commands/ai/extract.js
Outdated
| required: false, | ||
| description: 'The AI agent to be used for the extraction.', | ||
| parse(input) { | ||
| return JSON.parse(input); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add try catch
| try { | ||
| return JSON.parse(input); | ||
| } catch (error) { | ||
| throw ('Error parsing ai agent ', error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AI in upper case
src/commands/ai/extract.js
Outdated
| }), | ||
| 'ai-agent': Flags.string({ | ||
| required: false, | ||
| description: 'The AI agent to be used for the extraction.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be JSON, and example
test/commands/ai.test.js
Outdated
| description: 'Person first name', | ||
| prompt: 'What is the first name?', | ||
| displayName: 'First name', | ||
| options: [], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add testing for the options
3e3365a to
3082107
Compare
3082107 to
71a29c4
Compare
16935da to
71a29c4
Compare
75c906f to
5cf2710
Compare


No description provided.