├── LICENSE ├── README.md ├── rag_flow_webapi_pipeline_cs.py └── wechat.jpg /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # open-webui-pipeline-for-ragflow 2 | 一个好用又好看的大模型ui+rag在大模型问答类项目上简直太香了。open-webui+ragflow简直是绝配,既有ragflow的功能,又有open-webui漂亮强大的交互界面。使用open-webui中的pipeline技术在open-webui中调用ragflow的agent实现基于知识库的智能对话简直太棒了! 3 | ## 关于[open-webui](https://github.com/open-webui/open-webui) 4 | open-webui是一个非常好的大模型聊天集成软件,他提供的[pipelines](https://github.com/open-webui/pipelines)的方式,极大便利了集成其它大模型工具API到它的对话中来。目前版本在openwebui 0.5.20上测试通过。 5 | ## 关于[ragflow](https://github.com/infiniflow/ragflow) 6 | ragflow是我在实际项目中使用过的比较好用的大模型知识库开源项目,它成功支撑了我所负责的项目,用户在实际使用中也给予了很好的评价。目前版本在ragflow 0.17.0上测试通过。 7 | ## 关于本项目 8 | 在我所负责的大模型项目中,ragflow的agent很好的处理了基于知识库的问答,但不幸的是,ragflow并没有提供一个很好的对话交互界面,自带的界面仅仅是便于调试,完全无法让用户使用,因此需要将ragflow的agent集成进入一个比较成熟的对话界面软件,经过多种软件对比,我选择了open-webui。因为open-webui提供了一种集成技术[pipelines](https://github.com/open-webui/pipelines)。因此我开发了可以把在ragflow中所开发的agent集成入open-webui的[pipelines](https://github.com/open-webui/pipelines)。因为觉得好用,也想分享给有需的人,完全免费的分享,没有任何版权协议限制,您可以随便使用。仅仅是希望您不吝赐星一枚^_^ 9 | ## 联系我 10 | 如果有好的想法或发现了什么问题,请您一定要告诉我哦。 11 | 我的微信:qiuzhiyushi 12 | 13 | ## 使用方法 14 | - 首先下载open-webui的[pipelines](https://github.com/open-webui/pipelines)项目 15 | - 启动这个项目后,参考[pipelines](https://github.com/open-webui/pipelines)的README,在open-webui中的配置好pipelines的链接 16 | - 配置好链接后,将本项目的open-webui-pipeline-for-ragflow.py在open-webui中上传后,配置以下四个参数: 17 | ### - API_KEY: ragflow的apikey 18 | ### - AGENT_ID: ragflow的agentid 19 | ### - HOST: ragflow的host(要以http://或https://开头) 20 | ### - PORT: ragflow的port 21 | 然后你就可以实现在open-webui中调用ragflow中的agent,并且拥有美观的交互界面了。 22 | -------------------------------------------------------------------------------- /rag_flow_webapi_pipeline_cs.py: -------------------------------------------------------------------------------- 1 | """ 2 | title: RagFlow Pipeline 3 | author: luyilong2015 4 | date: 2025-01-28 5 | version: 1.0 6 | license: MIT 7 | description: A pipeline for retrieving relevant information from a knowledge base using the RagFlow's Agent Interface. 8 | requirements: datasets>=2.6.1, sentence-transformers>=2.2.0 9 | """ 10 | #智能客服 11 | from typing import List, Union, Generator, Iterator, Optional 12 | from pydantic import BaseModel 13 | import requests 14 | import json 15 | 16 | #API_KEY: ragflow apikey 17 | #AGENT_ID: ragflow agentid 18 | #HOST: ragflow host start with http:// or https:// 19 | #PORT: ragflow port 20 | class Pipeline: 21 | class Valves(BaseModel): 22 | API_KEY: str 23 | AGENT_ID: str 24 | HOST: str 25 | PORT: str 26 | 27 | def __init__(self): 28 | self.session_id=None 29 | self.debug=True 30 | self.sessionKV={} 31 | self.valves = self.Valves( 32 | **{ 33 | "API_KEY": "", 34 | "AGENT_ID": "", 35 | "HOST":"", 36 | "PORT":"" 37 | } 38 | ) 39 | 40 | async def on_startup(self): 41 | pass 42 | 43 | async def on_shutdown(self): 44 | # This function is called when the server is stopped. 45 | pass 46 | async def inlet(self, body: dict, user: Optional[dict] = None) -> dict: 47 | # This function is called before the OpenAI API request is made. You can modify the form data before it is sent to the OpenAI API. 48 | print(f"inlet: {__name__}") 49 | if self.debug: 50 | chat_id=body['metadata']['chat_id'] 51 | print(f"inlet: {__name__} - chat_id:{chat_id}") 52 | if self.sessionKV.get(chat_id): 53 | self.session_id=self.sessionKV.get(chat_id) 54 | print(f"cache ragflow's session_id is : {self.session_id}") 55 | else: 56 | #创建session 57 | session_url = f"{self.valves.HOST}:{self.valves.PORT}/api/v1/agents/{self.valves.AGENT_ID}/sessions" 58 | session_headers = { 59 | 'content-Type': 'application/json', 60 | 'Authorization': 'Bearer '+self.valves.API_KEY 61 | } 62 | session_data={} 63 | session_response = requests.post(session_url, headers=session_headers, json=session_data) 64 | json_res=json.loads(session_response.text) 65 | self.session_id=json_res['data']['id'] 66 | self.sessionKV[chat_id]=self.session_id 67 | print(f"new ragflow's session_id is : {json_res['data']['id']}") 68 | #print(f"inlet: {__name__} - body:{body}") 69 | print(f"inlet: {__name__} - user:") 70 | print(user) 71 | return body 72 | 73 | async def outlet(self, body: dict, user: Optional[dict] = None) -> dict: 74 | # This function is called after the OpenAI API response is completed. You can modify the messages after they are received from the OpenAI API. 75 | print(f"outlet: {__name__}") 76 | if self.debug: 77 | print(f"outlet: {__name__} - body:") 78 | #print(body) 79 | print(f"outlet chat_id: {body['chat_id']}") 80 | print(f"outlet session_id: {body['session_id']}") 81 | print(f"outlet: {__name__} - user:") 82 | print(user) 83 | return body 84 | def pipe( 85 | self, user_message: str, model_id: str, messages: List[dict], body: dict 86 | ) -> Union[str, Generator, Iterator]: 87 | # This is where you can add your custom RAG pipeline. 88 | # Typically, you would retrieve relevant information from your knowledge base and synthesize it to generate a response. 89 | # print(messages) 90 | question_url = f"{self.valves.HOST}:{self.valves.PORT}/api/v1/agents/{self.valves.AGENT_ID}/completions" 91 | question_headers = { 92 | 'content-Type': 'application/json', 93 | 'Authorization': 'Bearer '+self.valves.API_KEY 94 | } 95 | question_data={'question':user_message, 96 | 'stream':True, 97 | 'session_id':self.session_id, 98 | 'lang':'Chinese'} 99 | question_response = requests.post(question_url, headers=question_headers,stream=True, json=question_data) 100 | if question_response.status_code == 200: 101 | # Process and yield each chunk from the response 102 | step=0 103 | for line in question_response.iter_lines(): 104 | if line: 105 | try: 106 | # Remove 'data: ' prefix and parse JSON 107 | json_data = json.loads(line.decode('utf-8')[5:]) 108 | # Extract and yield only the 'text' field from the nested 'data' object 109 | # pring reference 110 | if 'data' in json_data and json_data['data'] is not True and 'answer' in json_data['data'] and '* is running...' not in json_data['data']['answer'] : 111 | if 'chunks' in json_data['data']['reference']: 112 | referenceStr="\n\n### references\n\n" 113 | filesList=[] 114 | for chunk in json_data['data']['reference']['chunks']: 115 | if chunk['document_id'] not in filesList: 116 | filename = chunk['document_name'] 117 | parts = filename.split('.') 118 | last_part = parts[-1].strip() 119 | ext= last_part.lower() if last_part else '' 120 | referenceStr=referenceStr+f"\n\n - ["+chunk['document_name']+f"]({self.valves.HOST}:{self.valves.PORT}/document/{chunk['document_id']}?ext={ext}&prefix=document)" 121 | filesList.append(chunk['document_id']) 122 | #print(f"chunks is :{len(json_data['data']['reference']['chunks'])}") 123 | #print(f"chunks is :{json_data['data']['reference']['chunks']}") 124 | yield referenceStr 125 | else: 126 | #print(json_data['data']) 127 | yield json_data['data']['answer'][step:] 128 | step=len(json_data['data']['answer']) 129 | 130 | 131 | except json.JSONDecodeError: 132 | print(f"Failed to parse JSON: {line}") 133 | else: 134 | yield f"Workflow request failed with status code: {question_response.status_code}" 135 | -------------------------------------------------------------------------------- /wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyilong2015/open-webui-pipeline-for-ragflow/446577fa267480871cf8b0724639ec2e9f36a82f/wechat.jpg --------------------------------------------------------------------------------