From 8f4c1187f0f4d8cabfaf09c6266265b04da3529d Mon Sep 17 00:00:00 2001 From: zstar <65890619+zstar1003@users.noreply.github.com> Date: Sat, 7 Jun 2025 23:17:33 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=96=B0=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E6=95=B0=E6=8D=AE=E5=BA=93=E8=BF=9E=E6=8E=A5=E5=92=8C?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改数据库连接配置,统一使用 Docker 内部网络地址 - 更新环境变量配置,简化 Redis 和 MinIO 的配置 - 删除 Helm 相关文件,清理 Kubernetes 部署配置 - 移除 ChatGPT-on-WeChat 插件相关代码和配置 --- api/db/services/database.py | 6 +- docker/.env | 4 +- helm/.helmignore | 23 --- helm/Chart.yaml | 24 --- helm/templates/_helpers.tpl | 62 ------- helm/templates/elasticsearch-config.yaml | 13 -- helm/templates/elasticsearch.yaml | 111 ------------ helm/templates/env.yaml | 48 ------ helm/templates/infinity.yaml | 108 ------------ helm/templates/ingress.yaml | 43 ----- helm/templates/minio.yaml | 91 ---------- helm/templates/mysql-config.yaml | 9 - helm/templates/mysql.yaml | 96 ----------- helm/templates/ragflow.yaml | 94 ----------- helm/templates/ragflow_config.yaml | 75 --------- helm/templates/redis.yaml | 81 --------- helm/templates/tests/test-connection.yaml | 17 -- helm/values.yaml | 159 ------------------ .../chatgpt-on-wechat/plugins/README.md | 57 ------- .../chatgpt-on-wechat/plugins/__init__.py | 8 - .../chatgpt-on-wechat/plugins/config.json | 4 - .../chatgpt-on-wechat/plugins/ragflow_chat.py | 127 -------------- .../plugins/requirements.txt | 1 - intergrations/extension_chrome/README.md | 45 ----- .../assets/logo-with-text.png | Bin 8240 -> 0 bytes .../extension_chrome/assets/logo.png | Bin 94937 -> 0 bytes .../extension_chrome/assets/logo.svg | 29 ---- intergrations/extension_chrome/background.js | 17 -- intergrations/extension_chrome/content.js | 68 -------- .../extension_chrome/icons/icon-128x128.png | Bin 8649 -> 0 bytes .../extension_chrome/icons/icon-16x16.png | Bin 716 -> 0 bytes .../extension_chrome/icons/icon-48x48.png | Bin 3265 -> 0 bytes intergrations/extension_chrome/manifest.json | 34 ---- intergrations/extension_chrome/options.html | 39 ----- intergrations/extension_chrome/options.js | 36 ---- intergrations/extension_chrome/popup.html | 20 --- intergrations/extension_chrome/popup.js | 24 --- .../extension_chrome/styles/options.css | 91 ---------- .../extension_chrome/styles/popup.css | 20 --- management/server/database.py | 6 +- 40 files changed, 8 insertions(+), 1682 deletions(-) delete mode 100644 helm/.helmignore delete mode 100644 helm/Chart.yaml delete mode 100644 helm/templates/_helpers.tpl delete mode 100644 helm/templates/elasticsearch-config.yaml delete mode 100644 helm/templates/elasticsearch.yaml delete mode 100644 helm/templates/env.yaml delete mode 100644 helm/templates/infinity.yaml delete mode 100644 helm/templates/ingress.yaml delete mode 100644 helm/templates/minio.yaml delete mode 100644 helm/templates/mysql-config.yaml delete mode 100644 helm/templates/mysql.yaml delete mode 100644 helm/templates/ragflow.yaml delete mode 100644 helm/templates/ragflow_config.yaml delete mode 100644 helm/templates/redis.yaml delete mode 100644 helm/templates/tests/test-connection.yaml delete mode 100644 helm/values.yaml delete mode 100644 intergrations/chatgpt-on-wechat/plugins/README.md delete mode 100644 intergrations/chatgpt-on-wechat/plugins/__init__.py delete mode 100644 intergrations/chatgpt-on-wechat/plugins/config.json delete mode 100644 intergrations/chatgpt-on-wechat/plugins/ragflow_chat.py delete mode 100644 intergrations/chatgpt-on-wechat/plugins/requirements.txt delete mode 100644 intergrations/extension_chrome/README.md delete mode 100644 intergrations/extension_chrome/assets/logo-with-text.png delete mode 100644 intergrations/extension_chrome/assets/logo.png delete mode 100644 intergrations/extension_chrome/assets/logo.svg delete mode 100644 intergrations/extension_chrome/background.js delete mode 100644 intergrations/extension_chrome/content.js delete mode 100644 intergrations/extension_chrome/icons/icon-128x128.png delete mode 100644 intergrations/extension_chrome/icons/icon-16x16.png delete mode 100644 intergrations/extension_chrome/icons/icon-48x48.png delete mode 100644 intergrations/extension_chrome/manifest.json delete mode 100644 intergrations/extension_chrome/options.html delete mode 100644 intergrations/extension_chrome/options.js delete mode 100644 intergrations/extension_chrome/popup.html delete mode 100644 intergrations/extension_chrome/popup.js delete mode 100644 intergrations/extension_chrome/styles/options.css delete mode 100644 intergrations/extension_chrome/styles/popup.css diff --git a/api/db/services/database.py b/api/db/services/database.py index cb9d826..938fcd9 100644 --- a/api/db/services/database.py +++ b/api/db/services/database.py @@ -27,12 +27,12 @@ def is_running_in_docker(): if is_running_in_docker(): MYSQL_HOST = "mysql" MYSQL_PORT = 3306 - MINIO_HOST = os.getenv("MINIO_VISIT_HOST", "host.docker.internal") + MINIO_HOST = "minio" MINIO_PORT = 9000 ES_HOST = "es01" ES_PORT = 9200 - REDIS_HOST = os.getenv("REDIS_HOST", "redis") - REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) + REDIS_HOST = "redis" + REDIS_PORT = 6379 else: MYSQL_HOST = "localhost" MYSQL_PORT = int(os.getenv("MYSQL_PORT", "5455")) diff --git a/docker/.env b/docker/.env index 66befab..3b97fe4 100644 --- a/docker/.env +++ b/docker/.env @@ -50,8 +50,8 @@ MYSQL_PORT=5455 # The hostname where the MinIO service is exposed MINIO_HOST=minio -# minio上传文件时的ip地址,如需公网访问,可修改为公网ip地址 -MINIO_VISIT_HOST=host.docker.internal +# 访问minio文件时的ip地址,如需公网访问,可修改为公网ip地址 +MINIO_VISIT_HOST=localhost # The port used to expose the MinIO console interface to the host machine, # allowing EXTERNAL access to the web-based console running inside the Docker container. MINIO_CONSOLE_PORT=9001 diff --git a/helm/.helmignore b/helm/.helmignore deleted file mode 100644 index 0e8a0eb..0000000 --- a/helm/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/helm/Chart.yaml b/helm/Chart.yaml deleted file mode 100644 index 4dd5af1..0000000 --- a/helm/Chart.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v2 -name: ragflow -description: A Helm chart for deploying RAGFlow on Kubernetes - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "dev" diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl deleted file mode 100644 index 8afe440..0000000 --- a/helm/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "ragflow.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "ragflow.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "ragflow.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "ragflow.labels" -}} -helm.sh/chart: {{ include "ragflow.chart" . }} -{{ include "ragflow.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "ragflow.selectorLabels" -}} -app.kubernetes.io/name: {{ include "ragflow.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "ragflow.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "ragflow.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/helm/templates/elasticsearch-config.yaml b/helm/templates/elasticsearch-config.yaml deleted file mode 100644 index a43eabe..0000000 --- a/helm/templates/elasticsearch-config.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if eq .Values.env.DOC_ENGINE "elasticsearch" -}} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "ragflow.fullname" . }}-es-config -data: - node.name: "es01" - bootstrap.memory_lock: "false" - discovery.type: "single-node" - xpack.security.enabled: "true" - xpack.security.http.ssl.enabled: "false" - xpack.security.transport.ssl.enabled: "false" -{{- end -}} diff --git a/helm/templates/elasticsearch.yaml b/helm/templates/elasticsearch.yaml deleted file mode 100644 index 935c716..0000000 --- a/helm/templates/elasticsearch.yaml +++ /dev/null @@ -1,111 +0,0 @@ -{{- if eq .Values.env.DOC_ENGINE "elasticsearch" -}} -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "ragflow.fullname" . }}-es-data - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: elasticsearch -spec: - {{- with .Values.elasticsearch.storage.className }} - storageClassName: {{ . }} - {{- end }} - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.elasticsearch.storage.capacity }} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "ragflow.fullname" . }}-es - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: elasticsearch -spec: - replicas: 1 - selector: - matchLabels: - {{- include "ragflow.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: elasticsearch - {{- with .Values.elasticsearch.deployment.strategy }} - strategy: - {{- . | toYaml | nindent 4 }} - {{- end }} - template: - metadata: - labels: - {{- include "ragflow.labels" . | nindent 8 }} - app.kubernetes.io/component: elasticsearch - annotations: - checksum/config-es: {{ include (print $.Template.BasePath "/elasticsearch-config.yaml") . | sha256sum }} - checksum/config-env: {{ include (print $.Template.BasePath "/env.yaml") . | sha256sum }} - spec: - initContainers: - - name: fix-data-volume-permissions - image: alpine - command: - - sh - - -c - - "chown -R 1000:0 /usr/share/elasticsearch/data" - volumeMounts: - - mountPath: /usr/share/elasticsearch/data - name: es-data - - name: sysctl - image: busybox - securityContext: - privileged: true - runAsUser: 0 - command: ["sysctl", "-w", "vm.max_map_count=262144"] - containers: - - name: elasticsearch - image: elasticsearch:{{ .Values.env.STACK_VERSION }} - envFrom: - - secretRef: - name: {{ include "ragflow.fullname" . }}-env-config - - configMapRef: - name: {{ include "ragflow.fullname" . }}-es-config - ports: - - containerPort: 9200 - name: http - - containerPort: 9300 - name: transport - volumeMounts: - - mountPath: /usr/share/elasticsearch/data - name: es-data - {{- with .Values.elasticsearch.deployment.resources }} - resources: - {{- . | toYaml | nindent 10 }} - {{- end }} - securityContext: - capabilities: - add: - - "IPC_LOCK" - runAsUser: 1000 - # NOTE: fsGroup doesn't seem to - # work so use init container instead - # fsGroup: 1000 - allowPrivilegeEscalation: false - volumes: - - name: es-data - persistentVolumeClaim: - claimName: {{ include "ragflow.fullname" . }}-es-data ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ragflow.fullname" . }}-es - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: elasticsearch -spec: - selector: - {{- include "ragflow.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: elasticsearch - ports: - - protocol: TCP - port: 9200 - targetPort: http - type: {{ .Values.elasticsearch.service.type }} -{{- end -}} diff --git a/helm/templates/env.yaml b/helm/templates/env.yaml deleted file mode 100644 index 783c5cc..0000000 --- a/helm/templates/env.yaml +++ /dev/null @@ -1,48 +0,0 @@ -{{- /* -TODO: Split env vars into separate secrets so that each pod - only gets passed the secrets it really needs. -*/}} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "ragflow.fullname" . }}-env-config -type: Opaque -stringData: - {{- range $key, $val := .Values.env }} - {{- if $val }} - {{ $key }}: {{ quote $val }} - {{- end }} - {{- end }} - {{- /* - Use host names derived from internal cluster DNS - */}} - REDIS_HOST: {{ printf "%s-redis.%s.svc" (include "ragflow.fullname" .) .Release.Namespace }} - MYSQL_HOST: {{ printf "%s-mysql.%s.svc" (include "ragflow.fullname" .) .Release.Namespace }} - MINIO_HOST: {{ printf "%s-minio.%s.svc" (include "ragflow.fullname" .) .Release.Namespace }} - {{- /* - Fail if passwords are not provided in release values - */}} - REDIS_PASSWORD: {{ .Values.env.REDIS_PASSWORD | required "REDIS_PASSWORD is required" }} - {{- /* - NOTE: MySQL uses MYSQL_ROOT_PASSWORD env var but Ragflow container expects - MYSQL_PASSWORD so we need to define both as the same value here. - */}} - {{- with .Values.env.MYSQL_PASSWORD | required "MYSQL_PASSWORD is required" }} - MYSQL_PASSWORD: {{ . }} - MYSQL_ROOT_PASSWORD: {{ . }} - {{- end }} - {{- with .Values.env.MINIO_PASSWORD | required "MINIO_PASSWORD is required" }} - MINIO_PASSWORD: {{ . }} - MINIO_ROOT_PASSWORD: {{ . }} - {{- end }} - {{- /* - Only provide env vars for enabled doc engine - */}} - {{- if eq .Values.env.DOC_ENGINE "elasticsearch" }} - ES_HOST: {{ printf "%s-es.%s.svc" (include "ragflow.fullname" .) .Release.Namespace }} - ELASTIC_PASSWORD: {{ .Values.env.ELASTIC_PASSWORD | required "ELASTIC_PASSWORD is required" }} - {{- else if eq .Values.env.DOC_ENGINE "infinity" }} - INFINITY_HOST: {{ printf "%s-infinity.%s.svc" (include "ragflow.fullname" .) .Release.Namespace }} - {{- else }} - {{ fail "env.DOC_ENGINE must be either 'elasticsearch' or 'infinity'" }} - {{- end }} diff --git a/helm/templates/infinity.yaml b/helm/templates/infinity.yaml deleted file mode 100644 index 8560e78..0000000 --- a/helm/templates/infinity.yaml +++ /dev/null @@ -1,108 +0,0 @@ -{{- if eq .Values.env.DOC_ENGINE "infinity" -}} -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "ragflow.fullname" . }}-infinity - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: infinity -spec: - {{- with .Values.infinity.storage.className }} - storageClassName: {{ . }} - {{- end }} - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.infinity.storage.capacity }} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "ragflow.fullname" . }}-infinity - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: infinity -spec: - replicas: 1 - selector: - matchLabels: - {{- include "ragflow.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: infinity - {{- with .Values.infinity.deployment.strategy }} - strategy: - {{- . | toYaml | nindent 4 }} - {{- end }} - template: - metadata: - labels: - {{- include "ragflow.labels" . | nindent 8 }} - app.kubernetes.io/component: infinity - annotations: - checksum/config: {{ include (print $.Template.BasePath "/env.yaml") . | sha256sum }} - spec: - containers: - - name: infinity - image: {{ .Values.infinity.image.repository }}:{{ .Values.infinity.image.tag }} - envFrom: - - secretRef: - name: {{ include "ragflow.fullname" . }}-env-config - ports: - - containerPort: 23817 - name: thrift - - containerPort: 23820 - name: http - - containerPort: 5432 - name: psql - volumeMounts: - - mountPath: /var/infinity - name: infinity-data - {{- with .Values.infinity.deployment.resources }} - resources: - {{- . | toYaml | nindent 10 }} - {{- end }} - securityContext: - capabilities: - add: - - "NET_BIND_SERVICE" - seccompProfile: - type: RuntimeDefault - livenessProbe: - httpGet: - path: /admin/node/current - port: 23820 - initialDelaySeconds: 60 - periodSeconds: 10 - timeoutSeconds: 10 - failureThreshold: 120 - volumes: - - name: infinity-data - persistentVolumeClaim: - claimName: {{ include "ragflow.fullname" . }}-infinity ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ragflow.fullname" . }}-infinity - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: infinity -spec: - selector: - {{- include "ragflow.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: infinity - ports: - - protocol: TCP - port: 23817 - targetPort: thrift - name: thrift - - protocol: TCP - port: 23820 - targetPort: http - name: http - - protocol: TCP - port: 5432 - targetPort: psql - name: psql - type: {{ .Values.infinity.service.type }} -{{- end -}} diff --git a/helm/templates/ingress.yaml b/helm/templates/ingress.yaml deleted file mode 100644 index 43fbbe9..0000000 --- a/helm/templates/ingress.yaml +++ /dev/null @@ -1,43 +0,0 @@ -{{- if .Values.ingress.enabled -}} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ include "ragflow.fullname" . }} - labels: - {{- include "ragflow.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- with .Values.ingress.className }} - ingressClassName: {{ . }} - {{- end }} - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - {{- with .pathType }} - pathType: {{ . }} - {{- end }} - backend: - service: - name: {{ .Release.Name }} - port: - name: http - {{- end }} - {{- end }} -{{- end }} diff --git a/helm/templates/minio.yaml b/helm/templates/minio.yaml deleted file mode 100644 index 289007d..0000000 --- a/helm/templates/minio.yaml +++ /dev/null @@ -1,91 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "ragflow.fullname" . }}-minio - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: minio -spec: - {{- with .Values.minio.storage.className }} - storageClassName: {{ . }} - {{- end }} - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.minio.storage.capacity }} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: ragflow-minio-deployment - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: minio - annotations: - checksum/config: {{ include (print $.Template.BasePath "/env.yaml") . | sha256sum }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "ragflow.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: minio - {{- with .Values.minio.deployment.strategy }} - strategy: - {{- . | toYaml | nindent 4 }} - {{- end }} - template: - metadata: - labels: - {{- include "ragflow.labels" . | nindent 8 }} - app.kubernetes.io/component: minio - spec: - containers: - - name: minio - image: {{ .Values.minio.image.repository }}:{{ .Values.minio.image.tag }} - envFrom: - - secretRef: - name: {{ include "ragflow.fullname" . }}-env-config - args: - - server - - "--console-address=:9001" - - "/data" - ports: - - containerPort: 9000 - name: s3 - - containerPort: 9001 - name: console - {{- with .Values.minio.deployment.resources }} - resources: - {{- . | toYaml | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /data - name: minio-data - volumes: - - name: minio-data - persistentVolumeClaim: - claimName: {{ include "ragflow.fullname" . }}-minio ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ragflow.fullname" . }}-minio - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: minio -spec: - selector: - {{- include "ragflow.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: minio - ports: - - name: s3 - protocol: TCP - port: 9000 - targetPort: s3 - - name: console - protocol: TCP - port: 9001 - targetPort: console - type: {{ .Values.minio.service.type }} diff --git a/helm/templates/mysql-config.yaml b/helm/templates/mysql-config.yaml deleted file mode 100644 index dd85010..0000000 --- a/helm/templates/mysql-config.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: mysql-init-script -data: - init.sql: |- - CREATE DATABASE IF NOT EXISTS rag_flow; - USE rag_flow; diff --git a/helm/templates/mysql.yaml b/helm/templates/mysql.yaml deleted file mode 100644 index f47fc0e..0000000 --- a/helm/templates/mysql.yaml +++ /dev/null @@ -1,96 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "ragflow.fullname" . }}-mysql - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: mysql -spec: - {{- with .Values.mysql.storage.className }} - storageClassName: {{ . }} - {{- end }} - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.mysql.storage.capacity }} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "ragflow.fullname" . }}-mysql - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: mysql -spec: - replicas: 1 - selector: - matchLabels: - {{- include "ragflow.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: mysql - {{- with .Values.mysql.deployment.strategy }} - strategy: - {{- . | toYaml | nindent 4 }} - {{- end }} - template: - metadata: - labels: - {{- include "ragflow.labels" . | nindent 8 }} - app.kubernetes.io/component: mysql - annotations: - checksum/config-mysql: {{ include (print $.Template.BasePath "/mysql-config.yaml") . | sha256sum }} - checksum/config-env: {{ include (print $.Template.BasePath "/env.yaml") . | sha256sum }} - spec: - containers: - - name: mysql - image: {{ .Values.mysql.image.repository }}:{{ .Values.mysql.image.tag }} - envFrom: - - secretRef: - name: {{ include "ragflow.fullname" . }}-env-config - args: - - --max_connections=1000 - - --character-set-server=utf8mb4 - - --collation-server=utf8mb4_general_ci - - --default-authentication-plugin=mysql_native_password - - --tls_version=TLSv1.2,TLSv1.3 - - --init-file=/data/application/init.sql - - --disable-log-bin - ports: - - containerPort: 3306 - name: mysql - {{- with .Values.mysql.deployment.resources }} - resources: - {{- . | toYaml | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /var/lib/mysql - name: mysql-data - - mountPath: /data/application/init.sql - subPath: init.sql - readOnly: true - name: init-script-volume - volumes: - - name: mysql-data - persistentVolumeClaim: - claimName: {{ include "ragflow.fullname" . }}-mysql - - name: init-script-volume - configMap: - name: mysql-init-script ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ragflow.fullname" . }}-mysql - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: mysql -spec: - selector: - {{- include "ragflow.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: mysql - ports: - - protocol: TCP - port: 3306 - targetPort: mysql - type: {{ .Values.mysql.service.type }} diff --git a/helm/templates/ragflow.yaml b/helm/templates/ragflow.yaml deleted file mode 100644 index b1f8d1e..0000000 --- a/helm/templates/ragflow.yaml +++ /dev/null @@ -1,94 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "ragflow.fullname" . }} - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: ragflow -spec: - replicas: 1 - selector: - matchLabels: - {{- include "ragflow.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: ragflow - {{- with .Values.ragflow.deployment.strategy }} - strategy: - {{- . | toYaml | nindent 4 }} - {{- end }} - template: - metadata: - labels: - {{- include "ragflow.labels" . | nindent 8 }} - app.kubernetes.io/component: ragflow - annotations: - checksum/config-env: {{ include (print $.Template.BasePath "/env.yaml") . | sha256sum }} - checksum/config-ragflow: {{ include (print $.Template.BasePath "/ragflow_config.yaml") . | sha256sum }} - spec: - containers: - - name: ragflow - image: {{ .Values.env.RAGFLOW_IMAGE }} - ports: - - containerPort: 80 - name: http - - containerPort: 9380 - name: http-api - volumeMounts: - - mountPath: /etc/nginx/conf.d/ragflow.conf - subPath: ragflow.conf - name: nginx-config-volume - - mountPath: /etc/nginx/proxy.conf - subPath: proxy.conf - name: nginx-config-volume - - mountPath: /etc/nginx/nginx.conf - subPath: nginx.conf - name: nginx-config-volume - envFrom: - - secretRef: - name: {{ include "ragflow.fullname" . }}-env-config - {{- with .Values.ragflow.deployment.resources }} - resources: - {{- . | toYaml | nindent 10 }} - {{- end }} - volumes: - - name: nginx-config-volume - configMap: - name: nginx-config ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ragflow.fullname" . }} - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: ragflow -spec: - selector: - {{- include "ragflow.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: ragflow - ports: - - protocol: TCP - port: 80 - targetPort: http - name: http - type: {{ .Values.ragflow.service.type }} ---- -{{- if .Values.ragflow.api.service.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ .Release.Name }}-api - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: ragflow -spec: - selector: - {{- include "ragflow.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: ragflow - ports: - - protocol: TCP - port: 80 - targetPort: http-api - name: http-api - type: {{ .Values.ragflow.api.service.type }} -{{- end }} diff --git a/helm/templates/ragflow_config.yaml b/helm/templates/ragflow_config.yaml deleted file mode 100644 index 6967ecc..0000000 --- a/helm/templates/ragflow_config.yaml +++ /dev/null @@ -1,75 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: nginx-config -data: - ragflow.conf: | - server { - listen 80; - server_name _; - root /ragflow/web/dist; - - gzip on; - gzip_min_length 1k; - gzip_comp_level 9; - gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; - gzip_vary on; - gzip_disable "MSIE [1-6]\."; - - location ~ ^/(v1|api) { - proxy_pass http://localhost:9380; - include proxy.conf; - } - - location / { - index index.html; - try_files $uri $uri/ /index.html; - } - - # Cache-Control: max-age~@~AExpires - location ~ ^/static/(css|js|media)/ { - expires 10y; - access_log off; - } - } - proxy.conf: | - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_http_version 1.1; - proxy_set_header Connection ""; - proxy_buffering off; - proxy_read_timeout 3600s; - proxy_send_timeout 3600s; - nginx.conf: | - user root; - worker_processes auto; - - error_log /var/log/nginx/error.log notice; - pid /var/run/nginx.pid; - - events { - worker_connections 1024; - } - - http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - client_max_body_size 128M; - - include /etc/nginx/conf.d/ragflow.conf; - } diff --git a/helm/templates/redis.yaml b/helm/templates/redis.yaml deleted file mode 100644 index ef1e1b3..0000000 --- a/helm/templates/redis.yaml +++ /dev/null @@ -1,81 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "ragflow.fullname" . }}-redis - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: redis -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 8Gi ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "ragflow.fullname" . }}-redis - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: redis -spec: - replicas: 1 - selector: - matchLabels: - {{- include "ragflow.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: redis - {{- with .Values.redis.deployment.strategy }} - strategy: - {{- . | toYaml | nindent 4 }} - {{- end }} - template: - metadata: - labels: - {{- include "ragflow.labels" . | nindent 8 }} - app.kubernetes.io/component: redis - annotations: - checksum/config-env: {{ include (print $.Template.BasePath "/env.yaml") . | sha256sum }} - spec: - containers: - - name: redis - image: {{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }} - command: - - "sh" - - "-c" - - "exec redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 128mb --maxmemory-policy allkeys-lru" - envFrom: - - secretRef: - name: {{ include "ragflow.fullname" . }}-env-config - ports: - - containerPort: 6379 - name: redis - {{- with .Values.redis.deployment.resources }} - resources: - {{- . | toYaml | nindent 10 }} - {{- end }} - volumeMounts: - - mountPath: /data - name: redis-data - volumes: - - name: redis-data - persistentVolumeClaim: - claimName: {{ include "ragflow.fullname" . }}-redis ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ragflow.fullname" . }}-redis - labels: - {{- include "ragflow.labels" . | nindent 4 }} - app.kubernetes.io/component: redis -spec: - selector: - {{- include "ragflow.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: redis - ports: - - protocol: TCP - port: 6379 - targetPort: redis - type: {{ .Values.redis.service.type }} diff --git a/helm/templates/tests/test-connection.yaml b/helm/templates/tests/test-connection.yaml deleted file mode 100644 index f3d3a48..0000000 --- a/helm/templates/tests/test-connection.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: "{{ include "ragflow.fullname" . }}-test-connection" - labels: - {{- include "ragflow.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": test -spec: - containers: - - name: wget - image: busybox - command: - - 'wget' - args: - - {{ printf "%s.%s.svc" (include "ragflow.fullname" .) .Release.Namespace }} - restartPolicy: Never diff --git a/helm/values.yaml b/helm/values.yaml deleted file mode 100644 index 217a90b..0000000 --- a/helm/values.yaml +++ /dev/null @@ -1,159 +0,0 @@ -# Based on docker compose .env file -env: - # The type of doc engine to use. - # Available options: - # - `elasticsearch` (default) - # - `infinity` (https://github.com/infiniflow/infinity) - # DOC_ENGINE: elasticsearch - DOC_ENGINE: infinity - - # The version of Elasticsearch. - STACK_VERSION: "8.11.3" - - # The password for Elasticsearch - ELASTIC_PASSWORD: infini_rag_flow_helm - - # The password for MySQL - MYSQL_PASSWORD: infini_rag_flow_helm - # The database of the MySQL service to use - MYSQL_DBNAME: rag_flow - - # The username for MinIO. - MINIO_ROOT_USER: rag_flow - # The password for MinIO - MINIO_PASSWORD: infini_rag_flow_helm - - # The password for Redis - REDIS_PASSWORD: infini_rag_flow_helm - - # The RAGFlow Docker image to download. - # Defaults to the v0.17.2-slim edition, which is the RAGFlow Docker image without embedding models. - RAGFLOW_IMAGE: infiniflow/ragflow:v0.17.2-slim - # - # To download the RAGFlow Docker image with embedding models, uncomment the following line instead: - # RAGFLOW_IMAGE: infiniflow/ragflow:v0.17.2 - # - # The Docker image of the v0.17.2 edition includes: - # - Built-in embedding models: - # - BAAI/bge-large-zh-v1.5 - # - BAAI/bge-reranker-v2-m3 - # - maidalun1020/bce-embedding-base_v1 - # - maidalun1020/bce-reranker-base_v1 - # - Embedding models that will be downloaded once you select them in the RAGFlow UI: - # - BAAI/bge-base-en-v1.5 - # - BAAI/bge-large-en-v1.5 - # - BAAI/bge-small-en-v1.5 - # - BAAI/bge-small-zh-v1.5 - # - jinaai/jina-embeddings-v2-base-en - # - jinaai/jina-embeddings-v2-small-en - # - nomic-ai/nomic-embed-text-v1.5 - # - sentence-transformers/all-MiniLM-L6-v2 - # - # - - # The local time zone. - TIMEZONE: "Asia/Shanghai" - - # Uncomment the following line if you have limited access to huggingface.co: - # HF_ENDPOINT: https://hf-mirror.com - - # The maximum file size for each uploaded file, in bytes. - # You can uncomment this line and update the value if you wish to change 128M file size limit - # MAX_CONTENT_LENGTH: "134217728" - # After making the change, ensure you update `client_max_body_size` in nginx/nginx.conf correspondingly. - -ragflow: - deployment: - strategy: - resources: - service: - # Use LoadBalancer to expose the web interface externally - type: ClusterIP - api: - service: - enabled: true - type: ClusterIP - -infinity: - image: - repository: infiniflow/infinity - tag: v0.5.0 - storage: - className: - capacity: 5Gi - deployment: - strategy: - resources: - service: - type: ClusterIP - -elasticsearch: - storage: - className: - capacity: 20Gi - deployment: - strategy: - resources: - requests: - cpu: "4" - memory: "16Gi" - service: - type: ClusterIP - -minio: - image: - repository: quay.io/minio/minio - tag: RELEASE.2023-12-20T01-00-02Z - storage: - className: - capacity: 5Gi - deployment: - strategy: - resources: - service: - type: ClusterIP - -mysql: - image: - repository: mysql - tag: 8.0.39 - storage: - className: - capacity: 5Gi - deployment: - strategy: - resources: - service: - type: ClusterIP - -redis: - image: - repository: valkey/valkey - tag: 8 - storage: - className: - capacity: 5Gi - deployment: - strategy: - resources: - service: - type: ClusterIP - - -# This block is for setting up web service ingress. For more information, see: -# https://kubernetes.io/docs/concepts/services-networking/ingress/ -ingress: - enabled: false - className: "" - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: chart-example.local - paths: - - path: / - pathType: ImplementationSpecific - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local diff --git a/intergrations/chatgpt-on-wechat/plugins/README.md b/intergrations/chatgpt-on-wechat/plugins/README.md deleted file mode 100644 index c09643e..0000000 --- a/intergrations/chatgpt-on-wechat/plugins/README.md +++ /dev/null @@ -1,57 +0,0 @@ -RAGFlow Chat Plugin for ChatGPT-on-WeChat -========================================= - -This folder contains the source code for the `ragflow_chat` plugin, which extends the core functionality of the RAGFlow API to support conversational interactions using Retrieval-Augmented Generation (RAG). This plugin integrates seamlessly with the [ChatGPT-on-WeChat](https://github.com/zhayujie/chatgpt-on-wechat) project, enabling WeChat and other platforms to leverage the knowledge retrieval capabilities provided by RAGFlow in chat interactions. - -### Features -* **Conversational Interactions**: Combine WeChat's conversational interface with powerful RAG (Retrieval-Augmented Generation) capabilities. -* **Knowledge-Based Responses**: Enrich conversations by retrieving relevant data from external knowledge sources and incorporating them into chat responses. -* **Multi-Platform Support**: Works across WeChat, WeCom, and various other platforms supported by the ChatGPT-on-WeChat framework. - -### Plugin vs. ChatGPT-on-WeChat Configurations -**Note**: There are two distinct configuration files used in this setup—one for the ChatGPT-on-WeChat core project and another specific to the `ragflow_chat` plugin. It is important to configure both correctly to ensure smooth integration. - -#### ChatGPT-on-WeChat Root Configuration (`config.json`) -This file is located in the root directory of the [ChatGPT-on-WeChat](https://github.com/zhayujie/chatgpt-on-wechat) project and is responsible for defining the communication channels and overall behavior. For example, it handles the configuration for WeChat, WeCom, and other services like Feishu and DingTalk. - -Example `config.json` (for WeChat channel): -```json -{ - "channel_type": "wechatmp", - "wechatmp_app_id": "YOUR_APP_ID", - "wechatmp_app_secret": "YOUR_APP_SECRET", - "wechatmp_token": "YOUR_TOKEN", - "wechatmp_port": 80, - ... -} -``` - -This file can also be modified to support other communication platforms, such as: -- **Personal WeChat** (`channel_type: wx`) -- **WeChat Public Account** (`wechatmp` or `wechatmp_service`) -- **WeChat Work (WeCom)** (`wechatcom_app`) -- **Feishu** (`feishu`) -- **DingTalk** (`dingtalk`) - -For detailed configuration options, see the official [LinkAI documentation](https://docs.link-ai.tech/cow/multi-platform/wechat-mp). - -#### RAGFlow Chat Plugin Configuration (`plugins/ragflow_chat/config.json`) -This configuration is specific to the `ragflow_chat` plugin and is used to set up communication with the RAGFlow server. Ensure that your RAGFlow server is running, and update the plugin's `config.json` file with your server details: - -Example `config.json` (for `ragflow_chat`): -```json -{ - "ragflow_api_key": "YOUR_API_KEY", - "ragflow_host": "127.0.0.1:80" -} -``` - -This file must be configured to point to your RAGFlow instance, with the `ragflow_api_key` and `ragflow_host` fields set appropriately. The `ragflow_host` is typically your server's address and port number, and the `ragflow_api_key` is obtained from your RAGFlow API setup. - -### Requirements -Before you can use this plugin, ensure the following are in place: - -1. You have installed and configured [ChatGPT-on-WeChat](https://github.com/zhayujie/chatgpt-on-wechat). -2. You have deployed and are running the [RAGFlow](https://github.com/infiniflow/ragflow) server. - -Make sure both `config.json` files (ChatGPT-on-WeChat and RAGFlow Chat Plugin) are correctly set up as per the examples above. diff --git a/intergrations/chatgpt-on-wechat/plugins/__init__.py b/intergrations/chatgpt-on-wechat/plugins/__init__.py deleted file mode 100644 index f6ded86..0000000 --- a/intergrations/chatgpt-on-wechat/plugins/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from beartype.claw import beartype_this_package -from .ragflow_chat import RAGFlowChat - -beartype_this_package() - -__all__ = [ - "RAGFlowChat" -] diff --git a/intergrations/chatgpt-on-wechat/plugins/config.json b/intergrations/chatgpt-on-wechat/plugins/config.json deleted file mode 100644 index b09ff72..0000000 --- a/intergrations/chatgpt-on-wechat/plugins/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "api_key": "ragflow-***", - "host_address": "127.0.0.1:80" -} diff --git a/intergrations/chatgpt-on-wechat/plugins/ragflow_chat.py b/intergrations/chatgpt-on-wechat/plugins/ragflow_chat.py deleted file mode 100644 index fe96f39..0000000 --- a/intergrations/chatgpt-on-wechat/plugins/ragflow_chat.py +++ /dev/null @@ -1,127 +0,0 @@ -# -# Copyright 2025 The InfiniFlow Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import logging -import requests -from bridge.context import ContextType # Import Context, ContextType -from bridge.reply import Reply, ReplyType # Import Reply, ReplyType -from plugins import Plugin, register # Import Plugin and register -from plugins.event import Event, EventContext, EventAction # Import event-related classes - -@register(name="RAGFlowChat", desc="Use RAGFlow API to chat", version="1.0", author="Your Name") -class RAGFlowChat(Plugin): - def __init__(self): - super().__init__() - # Load plugin configuration - self.cfg = self.load_config() - # Bind event handling function - self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context - # Store conversation_id for each user - self.conversations = {} - logging.info("[RAGFlowChat] Plugin initialized") - - def on_handle_context(self, e_context: EventContext): - context = e_context['context'] - if context.type != ContextType.TEXT: - return # Only process text messages - - user_input = context.content.strip() - session_id = context['session_id'] - - # Call RAGFlow API to get a reply - reply_text = self.get_ragflow_reply(user_input, session_id) - if reply_text: - reply = Reply() - reply.type = ReplyType.TEXT - reply.content = reply_text - e_context['reply'] = reply - e_context.action = EventAction.BREAK_PASS # Skip the default processing logic - else: - # If no reply is received, pass to the next plugin or default logic - e_context.action = EventAction.CONTINUE - - def get_ragflow_reply(self, user_input, session_id): - # Get API_KEY and host address from the configuration - api_key = self.cfg.get("api_key") - host_address = self.cfg.get("host_address") - user_id = session_id # Use session_id as user_id - - if not api_key or not host_address: - logging.error("[RAGFlowChat] Missing configuration") - return "The plugin configuration is incomplete. Please check the configuration." - - headers = { - "Authorization": f"Bearer {api_key}", - "Content-Type": "application/json" - } - - # Step 1: Get or create conversation_id - conversation_id = self.conversations.get(user_id) - if not conversation_id: - # Create a new conversation - url_new_conversation = f"http://{host_address}/v1/api/new_conversation" - params_new_conversation = { - "user_id": user_id - } - try: - response = requests.get(url_new_conversation, headers=headers, params=params_new_conversation) - logging.debug(f"[RAGFlowChat] New conversation response: {response.text}") - if response.status_code == 200: - data = response.json() - if data.get("code") == 0: - conversation_id = data["data"]["id"] - self.conversations[user_id] = conversation_id - else: - logging.error(f"[RAGFlowChat] Failed to create conversation: {data.get('message')}") - return f"Sorry, unable to create a conversation: {data.get('message')}" - else: - logging.error(f"[RAGFlowChat] HTTP error when creating conversation: {response.status_code}") - return f"Sorry, unable to connect to RAGFlow API (create conversation). HTTP status code: {response.status_code}" - except Exception as e: - logging.exception("[RAGFlowChat] Exception when creating conversation") - return f"Sorry, an internal error occurred: {str(e)}" - - # Step 2: Send the message and get a reply - url_completion = f"http://{host_address}/v1/api/completion" - payload_completion = { - "conversation_id": conversation_id, - "messages": [ - { - "role": "user", - "content": user_input - } - ], - "quote": False, - "stream": False - } - - try: - response = requests.post(url_completion, headers=headers, json=payload_completion) - logging.debug(f"[RAGFlowChat] Completion response: {response.text}") - if response.status_code == 200: - data = response.json() - if data.get("code") == 0: - answer = data["data"]["answer"] - return answer - else: - logging.error(f"[RAGFlowChat] Failed to get answer: {data.get('message')}") - return f"Sorry, unable to get a reply: {data.get('message')}" - else: - logging.error(f"[RAGFlowChat] HTTP error when getting answer: {response.status_code}") - return f"Sorry, unable to connect to RAGFlow API (get reply). HTTP status code: {response.status_code}" - except Exception as e: - logging.exception("[RAGFlowChat] Exception when getting answer") - return f"Sorry, an internal error occurred: {str(e)}" diff --git a/intergrations/chatgpt-on-wechat/plugins/requirements.txt b/intergrations/chatgpt-on-wechat/plugins/requirements.txt deleted file mode 100644 index f229360..0000000 --- a/intergrations/chatgpt-on-wechat/plugins/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -requests diff --git a/intergrations/extension_chrome/README.md b/intergrations/extension_chrome/README.md deleted file mode 100644 index 63221b0..0000000 --- a/intergrations/extension_chrome/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Chrome Extension -``` -chrome-extension/ -│ -├── manifest.json         # Main configuration file for the extension -├── popup.html          # Main user interface of the extension -├── popup.js            # Script for the main interface -├── background.js       # Background script for the extension -├── content.js          # Script to interact with web pages -├── styles/ -│   └── popup.css       # CSS file for the popup -├── icons/ -│   ├── icon16.png      # 16x16 pixel icon -│   ├── icon48.png      # 48x48 pixel icon -│   └── icon128.png     # 128x128 pixel icon -├── assets/ -│   └── ...             # Directory for other assets (images, fonts, etc.) -├── scripts/ -│   ├── utils.js        # File containing utility functions -│   └── api.js          # File containing API call logic -└── README.md           # Instructions for using and installing the extension -``` - -# Installation -1. Open chrome://extensions/. -2. Enable Developer mode. -3. Click Load unpacked and select the project directory. -# Features -1. Interact with web pages. -2. Run in the background to handle logic. -# Usage -- Click the extension icon in the toolbar. -- Follow the instructions in the interface. -# Additional Notes -- **manifest.json**: This file is crucial as it defines the extension's metadata, permissions, and entry points. -- **background.js**: This script runs independently of any web page and can perform tasks such as listening for browser events, making network requests, and storing data. -- **content.js**: This script injects code into web pages to manipulate the DOM, modify styles, or communicate with the background script. -- **popup.html/popup.js**: These files create the popup that appears when the user clicks the extension icon. -icons: These icons are used to represent the extension in the browser's UI. -More Detailed Explanation -- **manifest.json**: Specifies the extension's name, version, permissions, and other details. It also defines the entry points for the background script, content scripts, and the popup. -- **background.js**: Handles tasks that need to run continuously, such as syncing data, listening for browser events, or controlling the extension's behavior. -- **content.js**: Interacts directly with the web page's DOM, allowing you to modify the content, style, or behavior of the page. -- **popup.html/popup.js**: Creates a user interface that allows users to interact with the extension. -Other files: These files can contain additional scripts, styles, or assets that are used by the extension. diff --git a/intergrations/extension_chrome/assets/logo-with-text.png b/intergrations/extension_chrome/assets/logo-with-text.png deleted file mode 100644 index b55b5e0422fab33cc279681e5d7572f1cd5226d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8240 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 O081I94y=~52>lLjMTxCg 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 aSCZN-kX7lT{mOzYziy48Zp>=S - - - - - - - - - - \ No newline at end of file diff --git a/intergrations/extension_chrome/background.js b/intergrations/extension_chrome/background.js deleted file mode 100644 index 3ed9644..0000000 --- a/intergrations/extension_chrome/background.js +++ /dev/null @@ -1,17 +0,0 @@ -chrome.runtime.onInstalled.addListener(() => { - console.log("Tiện ích đã được cài đặt!"); -}); - -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message.action === "PAGE_INFO") { - console.log( message); - - - chrome.storage.local.set({ pageInfo: message }, () => { - console.log("Page info saved to local storage."); - }); - - // Send a response to the content script - sendResponse({ status: "success", message: "Page info received and processed." }); - } -}); \ No newline at end of file diff --git a/intergrations/extension_chrome/content.js b/intergrations/extension_chrome/content.js deleted file mode 100644 index b77c968..0000000 --- a/intergrations/extension_chrome/content.js +++ /dev/null @@ -1,68 +0,0 @@ -(function () { - const extractElementData = (el) => { - const tag = el.tagName.toLowerCase(); - if ( - tag === "input" && - el.name !== "DXScript" && - el.name !== "DXMVCEditorsValues" && - el.name !== "DXCss" - ) { - return { - type: "input", - name: el.name, - value: - el.type === "checkbox" || el.type === "radio" - ? el.checked - ? el.value - : null - : el.value, - }; - } else if (tag === "select") { - const selectedOption = el.querySelector("option:checked"); - return { - type: "select", - name: el.name, - value: selectedOption ? selectedOption.value : null, - }; - } else if (tag.startsWith("h") && el.textContent.trim()) { - return { type: "header", tag, content: el.textContent.trim() }; - } else if ( - ["label", "span", "p", "b", "strong"].includes(tag) && - el.textContent.trim() - ) { - return { type: tag, content: el.textContent.trim() }; - } - }; - - const getElementValues = (els) => - Array.from(els).map(extractElementData).filter(Boolean); - - const getIframeInputValues = (iframe) => { - try { - const iframeDoc = iframe.contentWindow.document; - return getElementValues( - iframeDoc.querySelectorAll("input, select, header, label, span, p") - ); - } catch (e) { - console.error("Can't access iframe:", e); - return []; - } - }; - - const inputValues = getElementValues( - document.querySelectorAll("input, select, header, label, span, p") - ); - const iframeInputValues = Array.from(document.querySelectorAll("iframe")).map( - getIframeInputValues - ); - - return ` - ## input values\n - \`\`\`json\n - ${JSON.stringify(inputValues)}\n - \`\`\`\n - ## iframe input values\n - \`\`\`json\n - ${JSON.stringify(iframeInputValues)}\n - \`\`\``; -})(); diff --git a/intergrations/extension_chrome/icons/icon-128x128.png b/intergrations/extension_chrome/icons/icon-128x128.png deleted file mode 100644 index 500b27a1d9018f3a8746237027a1b66348585520..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8649 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 diff --git a/intergrations/extension_chrome/manifest.json b/intergrations/extension_chrome/manifest.json deleted file mode 100644 index e30b89c..0000000 --- a/intergrations/extension_chrome/manifest.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "manifest_version": 3, - "name": "Ragflow Extension", - "description": "Ragflow for Chrome", - "version": "1.0", - "options_page": "options.html", - - "permissions": ["activeTab", "scripting", "storage"], - "background": { - "service_worker": "background.js" - }, - - "action": { - "default_popup": "popup.html", - "default_icon": { - "16": "icons/icon-16x16.png", - "48": "icons/icon-48x48.png", - "128": "icons/icon-128x128.png" - } - }, - - "content_scripts": [ - { - "matches": [""], - "js": ["content.js"], - "css": ["styles/popup.css"] - } - ], - "icons": { - "16": "icons/icon-16x16.png", - "48": "icons/icon-48x48.png", - "128": "icons/icon-128x128.png" - } -} diff --git a/intergrations/extension_chrome/options.html b/intergrations/extension_chrome/options.html deleted file mode 100644 index b39625a..0000000 --- a/intergrations/extension_chrome/options.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - RagFlow option - - - - -
-
- -
-
- - - - - - - - - - - - - - -
-
- - - - \ No newline at end of file diff --git a/intergrations/extension_chrome/options.js b/intergrations/extension_chrome/options.js deleted file mode 100644 index d72a942..0000000 --- a/intergrations/extension_chrome/options.js +++ /dev/null @@ -1,36 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - - chrome.storage.sync.get(["baseURL", "from", "auth", "sharedID"], (result) => { - if (result.baseURL) { - document.getElementById("base-url").value = result.baseURL; - } - if (result.from) { - document.getElementById("from").value = result.from; - } - if (result.auth) { - document.getElementById("auth").value = result.auth; - } - if (result.sharedID) { - document.getElementById("shared-id").value = result.sharedID; - } - }); - - document.getElementById("save-config").addEventListener("click", () => { - const baseURL = document.getElementById("base-url").value; - const from = document.getElementById("from").value; - const auth = document.getElementById("auth").value; - const sharedID = document.getElementById("shared-id").value; - - chrome.storage.sync.set( - { - baseURL: baseURL, - from: from, - auth: auth, - sharedID: sharedID, - }, - () => { - alert("Successfully saved"); - } - ); - }); -}); diff --git a/intergrations/extension_chrome/popup.html b/intergrations/extension_chrome/popup.html deleted file mode 100644 index c69d010..0000000 --- a/intergrations/extension_chrome/popup.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - RAGFLOW - - - - -
- - -
- - - - \ No newline at end of file diff --git a/intergrations/extension_chrome/popup.js b/intergrations/extension_chrome/popup.js deleted file mode 100644 index 0a8bdab..0000000 --- a/intergrations/extension_chrome/popup.js +++ /dev/null @@ -1,24 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - chrome.storage.sync.get(["baseURL", "from", "auth", "sharedID"], (result) => { - if (result.baseURL && result.sharedID && result.from && result.auth) { - const iframeSrc = `${result.baseURL}chat/share?shared_id=${result.sharedID}&from=${result.from}&auth=${result.auth}`; - const iframe = document.querySelector("iframe"); - iframe.src = iframeSrc; - } - }); - chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { - chrome.scripting.executeScript( - { - target: { tabId: tabs[0].id }, - files: ["content.js"], - }, - (results) => { - if (results && results[0]) { - const getHtml = document.getElementById("getHtml"); - getHtml.value = results[0].result; - - } - } - ); - }); -}); diff --git a/intergrations/extension_chrome/styles/options.css b/intergrations/extension_chrome/styles/options.css deleted file mode 100644 index 1e3ded6..0000000 --- a/intergrations/extension_chrome/styles/options.css +++ /dev/null @@ -1,91 +0,0 @@ -#ragflow { - font-family: "Segoe UI", Arial, sans-serif; - margin: 0; - padding: 0; - display: flex; - justify-content: center; - align-items: center; - height: 600px; -} - -#ragflow .window { - display: flex; - flex-direction: column; - justify-content: space-between; - flex: 1; - overflow: hidden; -} -#ragflow #form-config { - background-color: #fff; - box-shadow: 0 0 15px rgba(0, 0, 0, 0.3); - display: flex; - flex-direction: column; - justify-content: space-between; - overflow: hidden; -} - -#ragflow .header { - background-color: #fff; - padding: 4px; - display: flex; - justify-content: space-between; - align-items: center; - flex-direction: row; -} - -#ragflow .header .title { - font-size: 16px; -} - -#ragflow .header .logo { - width: 100px; /* Adjust size as needed */ - height: auto; - margin-right: 10px; -} - -#ragflow .content { - padding: 20px; - display: flex; - flex-direction: column; - justify-content: space-between; -} - -#ragflow label { - font-weight: bold; - margin-bottom: 5px; -} - -#ragflow input, -#ragflow select { - width: 100%; - padding: 8px; - margin-bottom: 15px; - border: 1px solid #ccc; - border-radius: 5px; - box-sizing: border-box; -} - -#ragflow button { - background-color: #0078d4; - color: #fff; - padding: 10px; - border: none; - border-radius: 5px; - cursor: pointer; - font-size: 14px; -} - -#ragflow button:hover { - background-color: #005bb5; -} - -#ragflow #config-button { - display: flex; - position: absolute; - top: 2px; - right: 2px; - font-size: 22px; -} -#ragflow #config-button:hover { - cursor: pointer; -} diff --git a/intergrations/extension_chrome/styles/popup.css b/intergrations/extension_chrome/styles/popup.css deleted file mode 100644 index 90134f8..0000000 --- a/intergrations/extension_chrome/styles/popup.css +++ /dev/null @@ -1,20 +0,0 @@ -#ragflow { - font-family: "Segoe UI", Arial, sans-serif; - margin: 0; - padding: 0; - display: flex; - justify-content: center; - align-items: center; - width: 320px; -} - -#ragflow .window { - display: flex; - flex-direction: column; - justify-content: space-between; - flex: 1; - overflow: hidden; -} -#ragflow #output { - position: absolute; -} \ No newline at end of file diff --git a/management/server/database.py b/management/server/database.py index 84ca343..a069358 100644 --- a/management/server/database.py +++ b/management/server/database.py @@ -27,12 +27,12 @@ def is_running_in_docker(): if is_running_in_docker(): MYSQL_HOST = "mysql" MYSQL_PORT = 3306 - MINIO_HOST = os.getenv("MINIO_VISIT_HOST", "host.docker.internal") + MINIO_HOST = "minio" MINIO_PORT = 9000 ES_HOST = "es01" ES_PORT = 9200 - REDIS_HOST = os.getenv("REDIS_HOST", "redis") - REDIS_PORT = int(os.getenv("REDIS_PORT", "6379")) + REDIS_HOST = "redis" + REDIS_PORT = 6379 else: MYSQL_HOST = "localhost" MYSQL_PORT = int(os.getenv("MYSQL_PORT", "5455"))