Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
openai.api_key= os.environ.get('API_OPENAI')
|
3 |
+
AIRTABLE_API_KEY = os.environ.get('API_AIRTABLE')
|
4 |
+
|
5 |
+
import gradio as gr
|
6 |
+
import os
|
7 |
+
import csv
|
8 |
+
from langchain.vectorstores import Pinecone
|
9 |
+
from langchain.embeddings.openai import OpenAIEmbeddings
|
10 |
+
from langchain.chains import ConversationalRetrievalChain
|
11 |
+
from langchain.chat_models import ChatOpenAI
|
12 |
+
import openai
|
13 |
+
import pinecone
|
14 |
+
import datetime
|
15 |
+
from tqdm.autonotebook import tqdm
|
16 |
+
import requests
|
17 |
+
|
18 |
+
embeddings = OpenAIEmbeddings(openai_api_key=openai.api_key)
|
19 |
+
|
20 |
+
AIRTABLE_ENDPOINT = "https://api.airtable.com/v0/appv2hF1PzrseVdeW/data_m"
|
21 |
+
AIRTABLE_ENDPOINT_LOG = "https://api.airtable.com/v0/appv2hF1PzrseVdeW/log"
|
22 |
+
HEADERS = {
|
23 |
+
"Authorization": f"Bearer {AIRTABLE_API_KEY}",
|
24 |
+
"Content-Type": "application/json"
|
25 |
+
}
|
26 |
+
|
27 |
+
def get_text_by_name(name):
|
28 |
+
params = {
|
29 |
+
"filterByFormula": f"{{name}} = '{name}'"
|
30 |
+
}
|
31 |
+
response = requests.get(AIRTABLE_ENDPOINT, headers=HEADERS, params=params)
|
32 |
+
|
33 |
+
if response.status_code != 200:
|
34 |
+
print(f"Error fetching data. Status code: {response.status_code}. Content: {response.content}")
|
35 |
+
return None
|
36 |
+
|
37 |
+
records = response.json().get("records")
|
38 |
+
|
39 |
+
if not records:
|
40 |
+
print(f"No record found with name: {name}")
|
41 |
+
return None
|
42 |
+
|
43 |
+
# Assuming that names are unique, take the first record.
|
44 |
+
return records[0]["fields"].get("text")
|
45 |
+
|
46 |
+
def upload_to_airtable_log(date, question, answer, rating, comment):
|
47 |
+
data = {
|
48 |
+
"records": [{
|
49 |
+
"fields": {
|
50 |
+
"date": date,
|
51 |
+
"question": question,
|
52 |
+
"answer": answer,
|
53 |
+
"rating": rating,
|
54 |
+
"comment": comment
|
55 |
+
}
|
56 |
+
}]
|
57 |
+
}
|
58 |
+
response = requests.post(AIRTABLE_ENDPOINT_LOG, headers=HEADERS, json=data)
|
59 |
+
|
60 |
+
if response.status_code != 200:
|
61 |
+
print(f"Error uploading airtable (log ) Status code: {response.status_code}. Content: {response.content}")
|
62 |
+
else:
|
63 |
+
print(f"Successfully uploaded airtable log")
|
64 |
+
|
65 |
+
def query_gpt_3_5(prompt, context):
|
66 |
+
prompt = "Instruction: Твоя роль - кваліфікований співробітник саппорту у системи YouControl. Потрібно відповісти на питання від користувача з огляду на контекст. Контекст ми беремо з бази знань, але вона може бути не повна. Якщо контекст не коректний, то відповідай на свій розсуд або передай запит сапорту, про контекс нічого не пишемо у відповіді."+"""
|
67 |
+
"""+ "question:" + prompt + """
|
68 |
+
context:""" + context + """
|
69 |
+
answer:"""
|
70 |
+
completion = openai.ChatCompletion.create(
|
71 |
+
model="gpt-4-0613",
|
72 |
+
messages=[
|
73 |
+
{"role": "user", "content": prompt}
|
74 |
+
]
|
75 |
+
)
|
76 |
+
return completion.choices[0].message.content
|
77 |
+
|
78 |
+
def print_docs(docs):
|
79 |
+
for doc in docs:
|
80 |
+
print(f"Chunk: {doc.page_content}")
|
81 |
+
print(f"Content: {doc.metadata['source']}\n")
|
82 |
+
|
83 |
+
# initialize pinecone
|
84 |
+
pinecone.init(
|
85 |
+
api_key="078ea261-eaa8-4920-8af6-0870f7f8a096", # find at app.pinecone.io
|
86 |
+
environment="eu-west4-gcp" # next to api key in console
|
87 |
+
)
|
88 |
+
|
89 |
+
index_name = "yc-faq"
|
90 |
+
vectorstore = Pinecone.from_existing_index(index_name, embeddings)
|
91 |
+
|
92 |
+
def ask_yc_bot(question):
|
93 |
+
if (len(question)<3 ): return "Не зрозумів питання"
|
94 |
+
docs = vectorstore.similarity_search(question)
|
95 |
+
print_docs(docs)
|
96 |
+
source_name = docs[0].metadata['source']
|
97 |
+
file_name = source_name.replace("/content/drive/MyDrive/yc-bot/faq/", "")
|
98 |
+
result_text = get_text_by_name(file_name)
|
99 |
+
context = ""
|
100 |
+
if result_text:
|
101 |
+
print(f"Text for '{file_name}' is: {result_text}")
|
102 |
+
context = context + result_text
|
103 |
+
|
104 |
+
|
105 |
+
|
106 |
+
#print (len(context))
|
107 |
+
result = query_gpt_3_5(question, context)
|
108 |
+
result = result + """
|
109 |
+
--------------------------------------------------------
|
110 |
+
[CONTEXT]
|
111 |
+
""" + context
|
112 |
+
return result
|
113 |
+
|
114 |
+
|
115 |
+
def comment_bot(slider_value, comment_text, question_text, answer_text):
|
116 |
+
date_d = datetime.datetime.now().date()
|
117 |
+
date_string = date_d.isoformat()
|
118 |
+
upload_to_airtable_log(date_string, question_text, answer_text, slider_value, comment_text)
|
119 |
+
|
120 |
+
return " " # Если функция должна что-то возвращать, замените это на нужный вывод
|
121 |
+
|
122 |
+
import gradio as gr
|
123 |
+
|
124 |
+
description = """<h1>YC - FAQ_BOT</h1>
|
125 |
+
"""
|
126 |
+
|
127 |
+
demo = gr.Blocks()
|
128 |
+
|
129 |
+
with demo:
|
130 |
+
gr.HTML(description)
|
131 |
+
with gr.Row():
|
132 |
+
with gr.Column(scale=1):
|
133 |
+
text = gr.Textbox(lines=7, label = "Вопрос?")
|
134 |
+
b1 = gr.Button("Спросить")
|
135 |
+
with gr.Column(scale=2):
|
136 |
+
answer = gr.Textbox(lines=10, label = "Ответ:")
|
137 |
+
|
138 |
+
with gr.Row():
|
139 |
+
radio = gr.Radio(label="Рейтинг ответа", choices=["Нет", "1", "2", "3", "4", "5"], value="Нет")
|
140 |
+
comment = gr.Textbox(lines=2, label = "Комментарий")
|
141 |
+
with gr.Row():
|
142 |
+
b2 = gr.Button("Прокомментировать ответ ")
|
143 |
+
|
144 |
+
inp_2 = [radio, comment, text, answer]
|
145 |
+
b1.click(ask_yc_bot, inputs=text, outputs=answer)
|
146 |
+
b2.click(comment_bot, inputs=inp_2, outputs=comment)
|
147 |
+
|
148 |
+
|
149 |
+
demo.launch(share=False, debug=True)
|