Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat frontend api refactor #11

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {

Check failure on line 1 in .eslintrc.js

View workflow job for this annotation

GitHub Actions / autofix

'module' is not defined

Check failure on line 1 in .eslintrc.js

View workflow job for this annotation

GitHub Actions / autofix

'module' is not defined
root: true,
parser: '@typescript-eslint/parser',
extends: [
Expand All @@ -19,5 +19,6 @@
'no-console': 'warn',
'prefer-const': 'error',
'no-var': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
},
};
4 changes: 4 additions & 0 deletions .vscode/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"cSpell.words": ["upsert"]
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Still on progress

CodeFox
LOGO
![](./assets/WechatIMG1000.svg)
![](./assets/WechatIMG1000.svg)
2 changes: 1 addition & 1 deletion backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import { join } from 'path';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from './user/user.module';
import { User } from './user/user.model';

Check warning on line 8 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'User' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 8 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'User' is defined but never used. Allowed unused vars must match /^_/u
import { AuthModule } from './auth/auth.module';
import { ProjectModule } from './project/project.module';
import { TokenModule } from './token/token.module';
import { ConfigModule, ConfigService } from '@nestjs/config';

Check warning on line 12 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'ConfigService' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 12 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'ConfigService' is defined but never used. Allowed unused vars must match /^_/u
import { JwtModule } from '@nestjs/jwt';

Check warning on line 13 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'JwtModule' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 13 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'JwtModule' is defined but never used. Allowed unused vars must match /^_/u
import { JwtCacheService } from './auth/jwt-cache.service';

Check warning on line 14 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'JwtCacheService' is defined but never used. Allowed unused vars must match /^_/u

Check warning on line 14 in backend/src/app.module.ts

View workflow job for this annotation

GitHub Actions / autofix

'JwtCacheService' is defined but never used. Allowed unused vars must match /^_/u
import { ChatModule } from './chat/chat.module';

@Module({
Expand All @@ -19,7 +19,7 @@
ConfigModule.forRoot({ isGlobal: true }),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
autoSchemaFile: join(process.cwd(), '../frontend/src/graphql/schema.gql'),
sortSchema: true,
playground: true,
installSubscriptionHandlers: true,
Expand Down
5 changes: 3 additions & 2 deletions backend/src/chat/chat.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ChatCompletionDelta {
@Field({ nullable: true })
content?: string;
}

@ObjectType('ChatCompletionChunkType')
export class ChatCompletionChunk {
@Field()
Expand All @@ -20,7 +21,7 @@ export class ChatCompletionChunk {
model: string;

@Field({ nullable: true })
system_fingerprint: string | null;
systemFingerprint: string | null;

@Field(() => [ChatCompletionChoice])
choices: ChatCompletionChoice[];
Expand All @@ -35,7 +36,7 @@ class ChatCompletionChoice {
delta: ChatCompletionDelta;

@Field({ nullable: true })
finish_reason: string | null;
finishReason: string | null;
}

@InputType('ChatInputType')
Expand Down
21 changes: 20 additions & 1 deletion backend/src/chat/chat.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Resolver, Subscription, Args } from '@nestjs/graphql';
import {
Resolver,
Subscription,
Args,
Field,
ObjectType,
Query,
} from '@nestjs/graphql';
import { ChatCompletionChunk, ChatInput } from './chat.model';
import { ChatProxyService } from './chat.service';

Expand All @@ -24,4 +31,16 @@ export class ChatResolver {
throw new Error('Chat stream failed');
}
}

@Query(() => ModelTags)
async modelTags() {
//TODO: model tags api
return { tags: ['gpt-3', 'gpt-4', 'davinci'] };
}
}

@ObjectType('ModelTags')
export class ModelTags {
@Field(() => [String])
tags: string[];
}
Binary file modified backend/src/database.sqlite
Binary file not shown.
12 changes: 12 additions & 0 deletions backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ import 'reflect-metadata';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
origin: '*',
credentials: true,
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: [
'Content-Type',
'Accept',
'Authorization',
'Access-Control-Allow-Origin',
'Access-Control-Allow-Credentials',
],
});
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
3 changes: 2 additions & 1 deletion frontend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"extends": "next/core-web-vitals"
"extends": "next/core-web-vitals",
"ignorePatterns": ["src/graphql/type.ts", "src/graphql/**/*"]
}
11 changes: 11 additions & 0 deletions frontend/.tmuxinator/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: frontend-dev
root: ./

windows:
- editor:
layout: even-horizontal
panes:
- next:
- pnpm dev
- codegen:
- pnpm generate:watch
135 changes: 1 addition & 134 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,134 +1 @@
<div align="center">
<img src="ollama-nextjs-ui.gif">
</div>

<h1 align="center">
Fully-featured & beautiful web interface for Ollama LLMs
</h1>

<div align="center">

![GitHub Repo stars](https://img.shields.io/github/stars/jakobhoeg/nextjs-ollama-llm-ui)

</div>

Get up and running with Large Language Models **quickly**, **locally** and even **offline**.
This project aims to be the easiest way for you to get started with LLMs. No tedious and annoying setup required!

# Features ✨

- **Beautiful & intuitive UI:** Inspired by ChatGPT, to enhance similarity in the user experience.
- **Fully local:** Stores chats in localstorage for convenience. No need to run a database.
- **Fully responsive:** Use your phone to chat, with the same ease as on desktop.
- **Easy setup:** No tedious and annoying setup required. Just clone the repo and you're good to go!
- **Code syntax highligting:** Messages that include code, will be highlighted for easy access.
- **Copy codeblocks easily:** Easily copy the highlighted code with one click.
- **Download/Pull & Delete models:** Easily download and delete models directly from the interface.
- **Switch between models:** Switch between models fast with a click.
- **Chat history:** Chats are saved and easily accessed.
- **Light & Dark mode:** Switch between light & dark mode.

# Preview

https://github.com/jakobhoeg/nextjs-ollama-llm-ui/assets/114422072/08eaed4f-9deb-4e1b-b87a-ba17d81b9a02

# Requisites ⚙️

To use the web interface, these requisites must be met:

1. Download [Ollama](https://ollama.com/download) and have it running. Or run it in a Docker container. Check the [docs](https://github.com/ollama/ollama) for instructions.
2. Node.js (18+) and npm is required. [Download](https://nodejs.org/en/download)

# Deploy your own to Vercel or Netlify in one click ✨

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fjakobhoeg%2Fnextjs-ollama-llm-ui&env=NEXT_PUBLIC_OLLAMA_URL&envDescription=Your%20Ollama%20URL) [![Deploy to Netlify Button](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/jakobhoeg/nextjs-ollama-llm-ui)

You'll need to set your [OLLAMA_ORIGINS](https://github.com/ollama/ollama/blob/main/docs/faq.md) environment variable on your machine that is running Ollama:

```
OLLAMA_ORIGINS="https://your-app.vercel.app/"
```

# Installation 📖

[![Packaging status](https://repology.org/badge/vertical-allrepos/nextjs-ollama-llm-ui.svg?columns=3)](https://repology.org/project/nextjs-ollama-llm-ui/versions)

Use a pre-build package from one of the supported package managers to run a local environment of the web interface.
Alternatively you can install from source with the instructions below.

> [!NOTE]
> If your frontend runs on something other than `http://localhost` or `http://127.0.0.1`, you'll need to set the OLLAMA_ORIGINS to your frontend url.
>
> This is also stated in the [documentation](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-do-i-configure-ollama-server):
>
> `Ollama allows cross-origin requests from 127.0.0.1 and 0.0.0.0 by default. Additional origins can be configured with OLLAMA_ORIGINS`

## Install from source

**1. Clone the repository to a directory on your pc via command prompt:**

```
git clone https://github.com/jakobhoeg/nextjs-ollama-llm-ui
```

**2. Open the folder:**

```
cd nextjs-ollama-llm-ui
```

**3. Rename the `.example.env` to `.env`:**

```
mv .example.env .env
```

**4. If your instance of Ollama is NOT running on the default ip-address and port, change the variable in the .env file to fit your usecase:**

```
NEXT_PUBLIC_OLLAMA_URL="http://localhost:11434"
```

**5. Install dependencies:**

```
npm install
```

**6. Start the development server:**

```
npm run dev
```

**5. Go to [localhost:3000](http://localhost:3000) and start chatting with your favourite model!**

# Upcoming features

This is a to-do list consisting of upcoming features.

- ✅ Voice input support
- ✅ Code syntax highlighting
- ✅ Ability to send an image in the prompt to utilize vision language models.
- ✅ Ability to regenerate responses
- ⬜️ Import and export chats

# Tech stack

[NextJS](https://nextjs.org/) - React Framework for the Web

[TailwindCSS](https://tailwindcss.com/) - Utility-first CSS framework

[shadcn-ui](https://ui.shadcn.com/) - UI component built using Radix UI and Tailwind CSS

[shadcn-chat](https://github.com/jakobhoeg/shadcn-chat) - Chat components for NextJS/React projects

[Framer Motion](https://www.framer.com/motion/) - Motion/animation library for React

[Lucide Icons](https://lucide.dev/) - Icon library

# Helpful links

[Medium Article](https://medium.com/@bartek.lewicz/launch-your-own-chatgpt-clone-for-free-on-colab-shareable-and-online-in-less-than-10-minutes-da19e44be5eb) - How to launch your own ChatGPT clone for free on Google Colab. By Bartek Lewicz.

[Lobehub mention](https://lobehub.com/blog/5-ollama-web-ui-recommendation#5-next-js-ollama-llm-ui) - Five Excellent Free Ollama WebUI Client Recommendations
- we are using tmuxinator if you want to watch both codegen and dev server
33 changes: 33 additions & 0 deletions frontend/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
schema: './src/graphql/schema.gql',
generates: {
'src/graphql/type.tsx': {
plugins: [
'typescript',
'typescript-operations',
'typescript-resolvers',
'typescript-react-apollo',
],
config: {
withHooks: true,
useIndexSignature: true,
enumsAsTypes: true,
constEnums: true,
skipTypename: false,
dedupeOperationSuffix: true,
nonOptionalTypename: true,
preResolveTypes: true,
namingConvention: {
enumValues: 'keep',
},
scalars: {
Date: 'Date',
},
},
},
},
};

export default config;
21 changes: 17 additions & 4 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
"scripts": {
"dev": "next dev",
"start:dev": "next dev",
"start:dev-watch": "tmuxinator start -p .tmuxinator/build.yml",
"build": "next build",
"start": "next start",
"lint": "next lint --fix",
"format": "prettier --write \"src/**/*.ts\""
"format": "prettier --write \"src/**/*.ts\"",
"generate": "graphql-codegen",
"generate:watch": "graphql-codegen --watch"
},
"dependencies": {
"@apollo/client": "^3.11.8",
Expand All @@ -17,6 +20,7 @@
"@hookform/resolvers": "^3.9.0",
"@langchain/community": "^0.3.1",
"@langchain/core": "^0.3.3",
"@nestjs/common": "^10.4.6",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
Expand All @@ -28,17 +32,14 @@
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@types/dom-speech-recognition": "^0.0.4",
"ai": "^3.4.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"emoji-mart": "^5.6.0",
"framer-motion": "^11.5.6",
"graphql": "^16.9.0",
"langchain": "^0.3.2",
"lucide-react": "^0.445.0",
"next": "^14.2.13",
"next-themes": "^0.3.0",
"ollama-ai-provider": "^0.15.0",
"react": "^18.3.1",
"react-code-blocks": "^0.1.6",
"react-dom": "^18.3.1",
Expand All @@ -57,6 +58,16 @@
"zustand": "^5.0.0-rc.2"
},
"devDependencies": {
"@0no-co/graphqlsp": "^1.12.16",
"@graphql-codegen/cli": "^5.0.3",
"@graphql-codegen/typescript": "^4.1.0",
"@graphql-codegen/typescript-operations": "^4.3.0",
"@graphql-codegen/typescript-react-apollo": "^4.3.2",
"@graphql-codegen/typescript-resolvers": "^4.3.0",
"@parcel/watcher": "^2.4.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.2",
"@testing-library/react": "^16.0.1",
"@types/jest": "^29.5.14",
"@types/node": "^22.5.5",
"@types/react": "^18.3.8",
Expand All @@ -66,9 +77,11 @@
"eslint": "8.57.1",
"eslint-config-next": "14.2.13",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.12",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
}
Loading
Loading