From cb2cbf500ca4de3d31c8123e237274c271b601dd Mon Sep 17 00:00:00 2001
From: balibabu <cike8899@users.noreply.github.com>
Date: Thu, 11 Apr 2024 18:17:45 +0800
Subject: [PATCH] feat: support Xinference (#319)

### What problem does this PR solve?

support xorbitsai inference as model provider

Issue link:#299

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
---
 web/src/assets/svg/enable.svg                 |  9 ++---
 web/src/assets/svg/llm/xinference.svg         | 39 +++++++++++++++++++
 web/src/locales/en.ts                         |  3 +-
 web/src/locales/zh.ts                         |  3 +-
 web/src/pages/user-setting/constants.tsx      |  2 +
 .../pages/user-setting/setting-model/hooks.ts |  9 ++++-
 .../user-setting/setting-model/index.tsx      | 14 ++++---
 .../setting-model/ollama-modal/index.tsx      | 13 ++++---
 web/src/pages/user-setting/utils.ts           |  4 ++
 9 files changed, 77 insertions(+), 19 deletions(-)
 create mode 100644 web/src/assets/svg/llm/xinference.svg
 create mode 100644 web/src/pages/user-setting/utils.ts

diff --git a/web/src/assets/svg/enable.svg b/web/src/assets/svg/enable.svg
index bf1535b..49c42a2 100644
--- a/web/src/assets/svg/enable.svg
+++ b/web/src/assets/svg/enable.svg
@@ -1,10 +1,9 @@
 <svg t="1712735583481" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6804"
     width="22" height="22">
     <path
-        d="M512 0a512 512 0 1 0 0 1024A512 512 0 0 0 512 0z m0 910.222222A398.222222 398.222222 0 1 1 512 113.777778a398.222222 398.222222 0 0 1 0 796.444444z"
-        fill="#ABEFC6" p-id="6805"></path>
+        d="M 512 0 a 512 512 0 1 0 0 1024 A 512 512 0 0 0 512 0 z m 0 990.2 A 438.2 438.2 0 1 1 512 33.8 a 438.2 438.2 0 0 1 0 956.4 z"
+        fill="#abefc6" p-id="6805"></path>
 
-    <path
-        d="M448.056889 584.305778L322.389333 458.638222 243.541333 537.543111l205.596445 205.539556h0.056889l0.512 0.512 325.859555-325.859556-80.440889-80.440889z"
-        fill="#17B26A" p-id="6806"></path>
+    <path d="M 448.1 584.3 L 322.4 458.6 L 243.5 537.5 l 205.6 205.5 h 0.1 l 0.5 0.5 l 325.9 -325.9 l -80.4 -80.4 z"
+        fill="#17b26a" p-id="6806"></path>
 </svg>
\ No newline at end of file
diff --git a/web/src/assets/svg/llm/xinference.svg b/web/src/assets/svg/llm/xinference.svg
new file mode 100644
index 0000000..8d2ab4f
--- /dev/null
+++ b/web/src/assets/svg/llm/xinference.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+    viewBox="0 0 283.46 283.46">
+    <defs>
+        <style>
+            .cls-1 {
+                fill: url(#_未命名的渐变_5-2);
+            }
+
+            .cls-2 {
+                fill: url(#_未命名的渐变_9);
+            }
+
+            .cls-3 {
+                fill: url(#_未命名的渐变_5);
+            }
+        </style>
+        <linearGradient id="_未命名的渐变_5" data-name="未命名的渐变 5" x1="27.03" y1="287.05" x2="253.15" y2="1.14"
+            gradientUnits="userSpaceOnUse">
+            <stop offset="0" stop-color="#e9a85e" />
+            <stop offset="1" stop-color="#f52b76" />
+        </linearGradient>
+        <linearGradient id="_未命名的渐变_5-2" data-name="未命名的渐变 5" x1="25.96" y1="286.21" x2="252.09" y2=".3"
+            xlink:href="#_未命名的渐变_5" />
+        <linearGradient id="_未命名的渐变_9" data-name="未命名的渐变 9" x1="-474.33" y1="476.58" x2="-160.37" y2="476.58"
+            gradientTransform="translate(669.07 -75.9) rotate(33.75)" gradientUnits="userSpaceOnUse">
+            <stop offset="0" stop-color="#6a0cf5" />
+            <stop offset="1" stop-color="#ab66f3" />
+        </linearGradient>
+    </defs>
+    <g>
+        <path class="cls-3"
+            d="M96.16,145.42c7.71,8.57,16.96,16.66,27.5,23.7,8.96,5.99,18.29,10.89,27.66,14.64,17.56-16.62,32.16-36.17,43.09-57.84L257.92,0l-110.84,87.19c-20.47,16.1-37.72,35.87-50.92,58.23Z" />
+        <path class="cls-1"
+            d="M87.08,223.86c-7.97-5.33-15.5-10.92-22.59-16.7l-38.49,76.31,69.17-54.4c-2.71-1.69-5.41-3.41-8.09-5.2Z" />
+    </g>
+    <path class="cls-2"
+        d="M229.81,101.27c20.81,27.65,26.93,58.36,12.79,79.51-20.63,30.88-76.59,29.69-124.98-2.64-48.39-32.34-70.89-83.58-50.25-114.46,14.14-21.15,44.86-27.25,78.36-18.6C87.76,20.46,32.59,22.86,11.22,54.85c-26.86,40.19,9.8,111.82,81.88,159.99,72.08,48.17,152.29,54.64,179.15,14.45,21.38-31.99,2.49-83.88-42.44-128.02Z" />
+</svg>
\ No newline at end of file
diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts
index 33fb8d9..4a4ca55 100644
--- a/web/src/locales/en.ts
+++ b/web/src/locales/en.ts
@@ -397,13 +397,14 @@ export default {
       upgrade: 'Upgrade',
       addLlmTitle: 'Add LLM',
       modelName: 'Model name',
+      modelUid: 'Model UID',
       modelNameMessage: 'Please input your model name!',
       modelType: 'Model type',
       modelTypeMessage: 'Please input your model type!',
       addLlmBaseUrl: 'Base url',
       baseUrlNameMessage: 'Please input your base url!',
       vision: 'Does it support Vision?',
-      ollamaLink: 'How to integrate Ollama',
+      ollamaLink: 'How to integrate {{name}}',
     },
     message: {
       registered: 'Registered!',
diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts
index 70a3b42..ad4741a 100644
--- a/web/src/locales/zh.ts
+++ b/web/src/locales/zh.ts
@@ -382,13 +382,14 @@ export default {
       upgrade: '升级',
       addLlmTitle: '添加 LLM',
       modelName: '模型名称',
+      modelUid: '模型UID',
       modelType: '模型类型',
       addLlmBaseUrl: '基础 Url',
       vision: '是否支持 Vision',
       modelNameMessage: '请输入模型名称!',
       modelTypeMessage: '请输入模型类型!',
       baseUrlNameMessage: '请输入基础 Url!',
-      ollamaLink: '如何集成 Ollama',
+      ollamaLink: '如何集成 {{name}}',
     },
     message: {
       registered: '注册成功',
diff --git a/web/src/pages/user-setting/constants.tsx b/web/src/pages/user-setting/constants.tsx
index 73df9c7..d91843c 100644
--- a/web/src/pages/user-setting/constants.tsx
+++ b/web/src/pages/user-setting/constants.tsx
@@ -14,3 +14,5 @@ export const UserSettingIconMap = {
 };
 
 export * from '@/constants/setting';
+
+export const LocalLlmFactories = ['Ollama', 'Xinference'];
diff --git a/web/src/pages/user-setting/setting-model/hooks.ts b/web/src/pages/user-setting/setting-model/hooks.ts
index 5e9bd8c..617c564 100644
--- a/web/src/pages/user-setting/setting-model/hooks.ts
+++ b/web/src/pages/user-setting/setting-model/hooks.ts
@@ -132,6 +132,7 @@ export const useSelectModelProvidersLoading = () => {
 
 export const useSubmitOllama = () => {
   const loading = useOneNamespaceEffectsLoading('settingModel', ['add_llm']);
+  const [selectedLlmFactory, setSelectedLlmFactory] = useState<string>('');
   const addLlm = useAddLlm();
   const {
     visible: llmAddingVisible,
@@ -149,11 +150,17 @@ export const useSubmitOllama = () => {
     [hideLlmAddingModal, addLlm],
   );
 
+  const handleShowLlmAddingModal = (llmFactory: string) => {
+    setSelectedLlmFactory(llmFactory);
+    showLlmAddingModal();
+  };
+
   return {
     llmAddingLoading: loading,
     onLlmAddingOk,
     llmAddingVisible,
     hideLlmAddingModal,
-    showLlmAddingModal,
+    showLlmAddingModal: handleShowLlmAddingModal,
+    selectedLlmFactory,
   };
 };
diff --git a/web/src/pages/user-setting/setting-model/index.tsx b/web/src/pages/user-setting/setting-model/index.tsx
index 272ffb5..cd570e7 100644
--- a/web/src/pages/user-setting/setting-model/index.tsx
+++ b/web/src/pages/user-setting/setting-model/index.tsx
@@ -25,6 +25,7 @@ import {
 } from 'antd';
 import { useCallback } from 'react';
 import SettingTitle from '../components/setting-title';
+import { isLocalLlmFactory } from '../utils';
 import ApiKeyModal from './api-key-modal';
 import {
   useSelectModelProvidersLoading,
@@ -43,6 +44,7 @@ const IconMap = {
   'ZHIPU-AI': 'zhipu',
   文心一言: 'wenxin',
   Ollama: 'ollama',
+  Xinference: 'xinference',
 };
 
 const LlmIcon = ({ name }: { name: string }) => {
@@ -89,7 +91,7 @@ const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
           <Col span={12} className={styles.factoryOperationWrapper}>
             <Space size={'middle'}>
               <Button onClick={handleApiKeyClick}>
-                {item.name === 'Ollama' ? t('addTheModel') : 'API-Key'}
+                {isLocalLlmFactory(item.name) ? t('addTheModel') : 'API-Key'}
                 <SettingOutlined />
               </Button>
               <Button onClick={handleShowMoreClick}>
@@ -147,12 +149,13 @@ const UserSettingModel = () => {
     showLlmAddingModal,
     onLlmAddingOk,
     llmAddingLoading,
+    selectedLlmFactory,
   } = useSubmitOllama();
 
   const handleApiKeyClick = useCallback(
     (llmFactory: string) => {
-      if (llmFactory === 'Ollama') {
-        showLlmAddingModal();
+      if (isLocalLlmFactory(llmFactory)) {
+        showLlmAddingModal(llmFactory);
       } else {
         showApiKeyModal({ llm_factory: llmFactory });
       }
@@ -161,8 +164,8 @@ const UserSettingModel = () => {
   );
 
   const handleAddModel = (llmFactory: string) => () => {
-    if (llmFactory === 'Ollama') {
-      showLlmAddingModal();
+    if (isLocalLlmFactory(llmFactory)) {
+      showLlmAddingModal(llmFactory);
     } else {
       handleApiKeyClick(llmFactory);
     }
@@ -252,6 +255,7 @@ const UserSettingModel = () => {
         hideModal={hideLlmAddingModal}
         onOk={onLlmAddingOk}
         loading={llmAddingLoading}
+        llmFactory={selectedLlmFactory}
       ></OllamaModal>
     </>
   );
diff --git a/web/src/pages/user-setting/setting-model/ollama-modal/index.tsx b/web/src/pages/user-setting/setting-model/ollama-modal/index.tsx
index b4805b6..9c16fcd 100644
--- a/web/src/pages/user-setting/setting-model/ollama-modal/index.tsx
+++ b/web/src/pages/user-setting/setting-model/ollama-modal/index.tsx
@@ -13,7 +13,8 @@ const OllamaModal = ({
   hideModal,
   onOk,
   loading,
-}: IModalProps<IAddLlmRequestBody>) => {
+  llmFactory,
+}: IModalProps<IAddLlmRequestBody> & { llmFactory: string }) => {
   const [form] = Form.useForm<FieldType>();
 
   const { t } = useTranslate('setting');
@@ -28,7 +29,7 @@ const OllamaModal = ({
     const data = {
       ...omit(values, ['vision']),
       model_type: modelType,
-      llm_factory: 'Ollama',
+      llm_factory: llmFactory,
     };
     console.info(data);
 
@@ -37,7 +38,7 @@ const OllamaModal = ({
 
   return (
     <Modal
-      title={t('addLlmTitle')}
+      title={t('addLlmTitle', { name: llmFactory })}
       open={visible}
       onOk={handleOk}
       onCancel={hideModal}
@@ -46,11 +47,11 @@ const OllamaModal = ({
         return (
           <Flex justify={'space-between'}>
             <a
-              href="https://github.com/infiniflow/ragflow/blob/main/docs/ollama.md"
+              href={`https://github.com/infiniflow/ragflow/blob/main/docs/${llmFactory.toLowerCase()}.md`}
               target="_blank"
               rel="noreferrer"
             >
-              {t('ollamaLink')}
+              {t('ollamaLink', { name: llmFactory })}
             </a>
             <Space>{originNode}</Space>
           </Flex>
@@ -76,7 +77,7 @@ const OllamaModal = ({
           </Select>
         </Form.Item>
         <Form.Item<FieldType>
-          label={t('modelName')}
+          label={t(llmFactory === 'Xinference' ? 'modelUid' : 'modelName')}
           name="llm_name"
           rules={[{ required: true, message: t('modelNameMessage') }]}
         >
diff --git a/web/src/pages/user-setting/utils.ts b/web/src/pages/user-setting/utils.ts
new file mode 100644
index 0000000..00094f8
--- /dev/null
+++ b/web/src/pages/user-setting/utils.ts
@@ -0,0 +1,4 @@
+import { LocalLlmFactories } from './constants';
+
+export const isLocalLlmFactory = (llmFactory: string) =>
+  LocalLlmFactories.some((x) => x === llmFactory);
-- 
GitLab