Skip to content

Commit

Permalink
Merge branch 'frevagpt' into auto-scroll
Browse files Browse the repository at this point in the history
  • Loading branch information
Bianca Wentzel committed Dec 12, 2024
2 parents 4ab9398 + c153a90 commit 95c61a9
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import { isEmpty } from "lodash";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";

import CodeBlock from "./CodeBlock";
import { replaceLinebreaks } from "../utils";

import * as constants from "../constants";

import { replaceLinebreaks } from "./utils";
import CodeBlock from "./CodeBlock";

class ChatBlock extends React.Component {
constructor(props) {
Expand All @@ -26,7 +28,7 @@ class ChatBlock extends React.Component {

renderImage(element) {
return (
<Col key={element.content} md={{ span: 10, offset: 0 }}>
<Col key={element.content} md={constants.BOT_COLUMN_STYLE}>
<img
className="w-100"
src={`data:image/jpeg;base64,${element.content}`}
Expand All @@ -39,7 +41,7 @@ class ChatBlock extends React.Component {
if (isEmpty(element.content[0])) return null;
else
return (
<Col md={{ span: 10, offset: 0 }} key={element.content}>
<Col md={constants.BOT_COLUMN_STYLE} key={element.content}>
<CodeBlock title={element.variant} code={element.content} />
</Col>
);
Expand All @@ -48,7 +50,10 @@ class ChatBlock extends React.Component {
renderUser(element) {
return (
<Col md={{ span: 10, offset: 2 }} key={element.content}>
<Card className="shadow-sm card-body border-0 border-bottom mb-3 bg-info">
<Card
className="shadow-sm card-body border-0 border-bottom mb-3"
style={{ backgroundColor: "#eee" }}
>
{element.content}
</Card>
</Col>
Expand All @@ -57,7 +62,7 @@ class ChatBlock extends React.Component {

renderError(element) {
return (
<Col md={{ span: 10, offset: 0 }} key={element.content}>
<Col md={constants.BOT_COLUMN_STYLE} key={element.content}>
<Card className="shadow-sm card-body border-0 border-bottom mb-3 bg-danger">
<span className="fw-bold">{element.variant}</span>
<ReactMarkdown>{replaceLinebreaks(element.content)}</ReactMarkdown>
Expand All @@ -68,7 +73,7 @@ class ChatBlock extends React.Component {

renderDefault(element) {
return (
<Col md={{ span: 10, offset: 0 }} key={element.content}>
<Col md={constants.BOT_COLUMN_STYLE} key={element.content}>
<Card className="shadow-sm card-body border-0 border-bottom mb-3 bg-light">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{replaceLinebreaks(element.content)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ import PropTypes from "prop-types";
import Highlight from "react-highlight";
import "highlight.js/styles/atom-one-light.css";

import { formatCode } from "./utils";
import { formatCode } from "../utils";

function CodeBlock(props) {
return (
<div className="mb-3">
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0">
<Accordion.Header>{props.title}</Accordion.Header>
<Accordion.Header>python</Accordion.Header>
<Accordion.Body>
<Highlight>{formatCode(props.title, props.code[0])}</Highlight>
<Highlight className="python">
{formatCode(props.title, props.code[0])}
</Highlight>
</Accordion.Body>
</Accordion.Item>
</Accordion>
Expand Down
88 changes: 88 additions & 0 deletions assets/js/Containers/FrevaGPT/components/PendingAnswerComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";

import { Col, Card, Spinner, Accordion, Row } from "react-bootstrap";

import Markdown from "react-markdown";

import Highlight from "react-highlight";
import "highlight.js/styles/atom-one-light.css";

import * as constants from "../constants";

function PendingAnswerComponent(props) {
const [renderedCode, setRenderedCode] = useState("");

useEffect(() => {
const parsedCode = renderCode(props.content);
if (parsedCode !== "") setRenderedCode(parsedCode);
}, [props.content]);

function renderCode(rawCode) {
let jsonCode = "";
let codeSnippets = "";

if (!rawCode.endsWith('"}')) jsonCode = rawCode + '"}';
else jsonCode = rawCode;

try {
const code = JSON.parse(jsonCode);
codeSnippets = code.code;
} catch (err) {
// console.error(err);
}
return codeSnippets;
}

function renderAnswer(props) {
switch (props.variant) {
case "Assistant":
return (
<Col md={constants.BOT_COLUMN_STYLE}>
<Card className="shadow-sm card-body border-0 border-bottom mb-3 bg-light">
<Markdown>{props.content}</Markdown>
</Card>
</Col>
);
case "Code":
case "CodeBlock":
return (
<Col md={constants.BOT_COLUMN_STYLE}>
<div className="mb-3">
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0">
<Accordion.Header>python</Accordion.Header>
<Accordion.Body>
<Highlight className="python">{renderedCode}</Highlight>
<span>
<Spinner size="sm" />
<span className="m-2">Analyzing...</span>
</span>
</Accordion.Body>
</Accordion.Item>
</Accordion>
</div>
</Col>
);
case "ServerHint":
return (
<Row className="mb-3">
<Col md={1}>
<Spinner />
</Col>
</Row>
);
default:
return null;
}
}

return renderAnswer(props);
}

PendingAnswerComponent.propTypes = {
content: PropTypes.string,
variant: PropTypes.string,
};

export default PendingAnswerComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Card } from "react-bootstrap";

import { browserHistory } from "react-router";

import { botRequests } from "./exampleRequests";
import { botRequests } from "../exampleRequests";

function SidePanel() {
function changeToThread(thread) {
Expand Down
1 change: 1 addition & 0 deletions assets/js/Containers/FrevaGPT/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const ADD_ELEMENT = "ADD_ELEMENT";
export const SET_CONVERSATION = "SET_CONVERSATION";
export const SET_THREAD = "SET_THREAD";
export const BOT_COLUMN_STYLE = { span: 10, offset: 0 };
37 changes: 30 additions & 7 deletions assets/js/Containers/FrevaGPT/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import { isEmpty, has } from "lodash";

import Spinner from "../../Components/Spinner";

import ChatBlock from "./ChatBlock";
import SidePanel from "./SidePanel";
import ChatBlock from "./components/ChatBlock";
import SidePanel from "./components/SidePanel";
import PendingAnswerComponent from "./components/PendingAnswerComponent";

import { objectToQueryString, truncate } from "./utils";

Expand Down Expand Up @@ -54,6 +55,8 @@ class FrevaGPT extends React.Component {
hideBotModelList: true,
botOkay: undefined,
showSuggestions: true,
dynamicAnswer: "",
dynamicVariant: "",
};

this.chatEndRef = React.createRef(null);
Expand Down Expand Up @@ -177,7 +180,6 @@ class FrevaGPT extends React.Component {
while (true) {
// eslint-disable-next-line no-await-in-loop
const { done, value } = await reader.read();
console.log('##', decoder.decode(value));
if (done) break;

const decodedValues = decoder.decode(value);
Expand All @@ -201,16 +203,27 @@ class FrevaGPT extends React.Component {
// if object has not same variant, add answer to conversation and override object
if (varObj.variant !== jsonBuffer.variant) {
this.props.dispatch(addElement(varObj));
this.setState({ dynamicAnswer: "", dynamicVariant: "" });
varObj = jsonBuffer;
} else {
// if object has same variant, add content
// eslint-disable-next-line no-lonely-if
if (
varObj.variant === "Code" ||
varObj.variant === "CodeOutput"
)
) {
varObj.content[0] = varObj.content[0] + jsonBuffer.content[0];
else varObj.content = varObj.content + jsonBuffer.content;
this.setState({
dynamicAnswer: varObj.content[0],
dynamicVariant: varObj.variant,
});
} else {
varObj.content = varObj.content + jsonBuffer.content;
this.setState({
dynamicAnswer: varObj.content,
dynamicVariant: varObj.variant,
});
}
}
} else {
// object is empty so add content
Expand Down Expand Up @@ -238,8 +251,13 @@ class FrevaGPT extends React.Component {
foundSomething = true;
break;
} catch (err) {
// ServerHints and CodeBlocks include nested JSON Objects
// eslint-disable-next-line no-console
console.error(err);
if (
!subBuffer.includes("ServerHint") &&
!subBuffer.includes("Code")
)
console.error(err);
}
}
}
Expand Down Expand Up @@ -325,9 +343,14 @@ class FrevaGPT extends React.Component {

<ChatBlock />

<PendingAnswerComponent
content={this.state.dynamicAnswer}
variant={this.state.dynamicVariant}
/>

<div ref={this.chatEndRef}/>

{this.state.loading ? (
{this.state.loading && !this.state.dynamicAnswer ? (
<Row className="mb-3">
<Col md={1}>
<Spinner />
Expand Down
35 changes: 31 additions & 4 deletions bot/proxyviews.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
from urllib.parse import urljoin

import requests
from django.conf import settings
from django.http import StreamingHttpResponse
from django.views import View
from djproxy.views import HttpProxy


class ChatBotProxy(HttpProxy):
"""A reverse proxy to forward requests to the databrowserAPI."""
class ChatBotProxy(View):
def get(self, request, *args, **kwargs):
path = request.path
base_url = urljoin(settings.CHAT_BOT_URL, path)
params = request.GET.dict()

base_url = urljoin(settings.CHAT_BOT_URL, "/api/chatbot/")
reverse_urls = [("/api/chatbot/", settings.CHAT_BOT_URL)]
try:
upstream_response = requests.get(base_url[:-1], params=params, stream=True)
upstream_response.raise_for_status()
except requests.RequestException as e:
return StreamingHttpResponse(
f"Error while connecting to the external API: {str(e)}",
status=502,
)

# Stream the content of the external API to the Django response
def stream():
for chunk in upstream_response.iter_content(chunk_size=8192):
if chunk:
yield chunk

response = StreamingHttpResponse(
stream(), content_type=upstream_response.headers.get("Content-Type")
)
response["Content-Disposition"] = upstream_response.headers.get(
"Content-Disposition", "inline"
)

return response
1 change: 1 addition & 0 deletions bot/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def reverse_proxy(request, path):
method="GET",
url=api_url,
params=all_parameters,
stream=True, # Enable streaming
timeout=100,
)
return response.content
Expand Down

0 comments on commit 95c61a9

Please sign in to comment.