feat: support aws bedrockruntime claude3 (#1328)

* feat: support aws bedrockruntime claude3

closes #622, closes #749, closes #1300

* fix: convert to aws claude model id

* fix: Update AWS adapter to handle stream completions and calculate usage metrics

Based on the file summaries provided, here are the important bullet points for the commit message:

- Add functionality to handle stream completion events from AWS in the relay/adaptor/aws/main.go file
- Marshall AWS response to OpenAI format and calculate usage metrics in the same file
- Implement a custom render function for streaming events in the same file
- Improve error handling for JSON unmarshalling and marshalling errors in the same file

* fix: Implement AWS handler with usage tracking and error handling

- Implemented streaming response handling for AWS handler
- Set response content type to text/event-stream
- Added error handling for failed marshaling/unmarshaling
- Updated return values to include `relaymodel.ErrorWithStatusCode` and `relaymodel.Usage`
- Improved error handling and response formatting for AWS adaptor

* fix: Refactor AWS Adapter for Improved Model Mapping and Error Handling

* Refactor AWS adapter to improve model management
  - Replace hardcoded model list in `adapter.go` with a function to get models from `awsModelIDMap`
  - Update `GetModelList` function to return model list directly
  - Add `GetChannelName` function to get channel name from `Adaptor` object
* Improve error handling and code organization in main.go
  - Replace switch statement with a map to map AWS model IDs to OpenAI model IDs
  - Return an error if the model is not found in the map
  - Use a single return statement instead of wrapping multiple return statements in the `awsModelID` function
  - Add a new error message for when the model is not found in the map in the `Handler` function

* fix: bug fix

* chore: change variable name & package

* chore: change variable name

* perf: update config related code

---------

Co-authored-by: JustSong <songquanpeng@foxmail.com>
This commit is contained in:
Laisky.Cai
2024-04-20 00:40:47 +08:00
committed by GitHub
parent 1a0b039bcf
commit fc9a784950
22 changed files with 566 additions and 198 deletions

View File

@@ -18,7 +18,7 @@
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build && mv -f build ../build/default",
"build": "react-scripts build && rm -rf ../build/default && mv -f build ../build/default",
"test": "react-scripts test",
"eject": "react-scripts eject"
},

View File

@@ -1,6 +1,7 @@
export const CHANNEL_OPTIONS = [
{ key: 1, text: 'OpenAI', value: 1, color: 'green' },
{ key: 14, text: 'Anthropic Claude', value: 14, color: 'black' },
{ key: 33, text: 'AWS Claude', value: 33, color: 'black' },
{ key: 3, text: 'Azure OpenAI', value: 3, color: 'olive' },
{ key: 11, text: 'Google PaLM2', value: 11, color: 'orange' },
{ key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
@@ -31,4 +32,4 @@ export const CHANNEL_OPTIONS = [
{ key: 9, text: '代理AI.LS', value: 9, color: 'yellow' },
{ key: 12, text: '代理API2GPT', value: 12, color: 'blue' },
{ key: 13, text: '代理AIGC2D', value: 13, color: 'purple' }
];
];

View File

@@ -54,6 +54,11 @@ const EditChannel = () => {
const [basicModels, setBasicModels] = useState([]);
const [fullModels, setFullModels] = useState([]);
const [customModel, setCustomModel] = useState('');
const [config, setConfig] = useState({
region: '',
sk: '',
ak: ''
});
const handleInputChange = (e, { name, value }) => {
setInputs((inputs) => ({ ...inputs, [name]: value }));
if (name === 'type') {
@@ -65,6 +70,10 @@ const EditChannel = () => {
}
};
const handleConfigChange = (e, { name, value }) => {
setConfig((inputs) => ({ ...inputs, [name]: value }));
};
const loadChannel = async () => {
let res = await API.get(`/api/channel/${channelId}`);
const { success, message, data } = res.data;
@@ -83,6 +92,7 @@ const EditChannel = () => {
data.model_mapping = JSON.stringify(JSON.parse(data.model_mapping), null, 2);
}
setInputs(data);
setConfig(JSON.parse(data.config));
setBasicModels(getChannelModels(data.type));
} else {
showError(message);
@@ -144,6 +154,13 @@ const EditChannel = () => {
}, []);
const submit = async () => {
// some provider as AWS need both AK and SK rather than a single key,
// so we need to combine them into a single key to achieve the best compatibility.
if (inputs.ak && inputs.sk) {
console.log(`combine ak ${inputs.ak} and sk ${inputs.sk}`, inputs.ak, inputs.sk);
inputs.key = `${inputs.ak}\n${inputs.sk}`;
}
if (!isEdit && (inputs.name === '' || inputs.key === '')) {
showInfo('请填写渠道名称和渠道密钥!');
return;
@@ -169,6 +186,7 @@ const EditChannel = () => {
let res;
localInputs.models = localInputs.models.join(',');
localInputs.group = localInputs.groups.join(',');
localInputs.config = JSON.stringify(config);
if (isEdit) {
res = await API.put(`/api/channel/`, { ...localInputs, id: parseInt(channelId) });
} else {
@@ -345,7 +363,9 @@ const EditChannel = () => {
fluid
multiple
search
onLabelClick={(e, { value }) => {copy(value).then()}}
onLabelClick={(e, { value }) => {
copy(value).then();
}}
selection
onChange={handleInputChange}
value={inputs.models}
@@ -392,7 +412,40 @@ const EditChannel = () => {
/>
</Form.Field>
{
batch ? <Form.Field>
inputs.type === 33 && (
<Form.Field>
<Form.Input
label='Region'
name='region'
required
placeholder={'regione.g. us-west-2'}
onChange={handleConfigChange}
value={config.region}
autoComplete=''
/>
<Form.Input
label='AK'
name='ak'
required
placeholder={'AWS IAM Access Key'}
onChange={handleConfigChange}
value={config.ak}
autoComplete=''
/>
<Form.Input
label='SK'
name='sk'
required
placeholder={'AWS IAM Secret Key'}
onChange={handleConfigChange}
value={config.sk}
autoComplete=''
/>
</Form.Field>
)
}
{
inputs.type !== 33 && (batch ? <Form.Field>
<Form.TextArea
label='密钥'
name='key'
@@ -413,10 +466,10 @@ const EditChannel = () => {
value={inputs.key}
autoComplete='new-password'
/>
</Form.Field>
</Form.Field>)
}
{
!isEdit && (
inputs.type !== 33 && !isEdit && (
<Form.Checkbox
checked={batch}
label='批量创建'
@@ -426,7 +479,7 @@ const EditChannel = () => {
)
}
{
inputs.type !== 3 && inputs.type !== 8 && inputs.type !== 22 && (
inputs.type !== 3 && inputs.type !== 33 && inputs.type !== 8 && inputs.type !== 22 && (
<Form.Field>
<Form.Input
label='代理'